前言

本篇文章记录了学习微信小程序时遇到的一些问题和知识点,学习材料是coderwhy老师的视频。

本地开发环境设定与修改

微信开发者工具将个人对工具做的所有配置都写入到了project.config.json文件中,当更换电脑或重装时,只需要载入同一个项目的代码包,开发者工具就自动会帮开发者恢复到当时开发项目时的个性化配置,其中会包括编辑器的颜色、代码上传时自动压缩等等一系列选项。

需要注意project.config.jsonproject.private.config.json两个文件的区别,private是个人的配置且优先级更高,以下来源于微信开发文档:

  1. 项目根目录中的 project.config.jsonproject.private.config.json 文件可以对项目进行配置,
  2. project.private.config.json 中的相同设置优先级高于 project.config.json
  3. 可以在 project.config.json 文件中配置公共的配置,在 project.private.config.json 配置个人的配置,可以将 project.private.config.json 写到 .gitignore 避免版本管理的冲突。
  4. project.private.config.json 中有的字段,开发者工具内的设置修改会优先覆盖 project.private.config.json 的内容。如在 project.private.config.jsonappid 字段,那么在 详情 - 基本信息 中修改了 appid,会写到 project.private.config.json 中,不会覆盖掉 project.config.jsonappid 字段的内容
  5. 开发阶段相关的设置修改优先同步到 project.private.config.json 中,但与最终编译产物有关的设置无法在 project.private.config.json 中生效,界面上的改动也不会同步到 project.private.config.json 文件中。详见 表格是否允许私有设置。

当需要更换版本、修改本地调试的设置时,打开开发工具右上角的详情,修改本地设置即可。

01-本地config配置

页面下拉刷新与上拉加载

针对单个页面(page)实现下拉刷新和上拉加载,需要用到onPullDownRefreshonReachBottom两个函数,对需要实现的页面配置page.js,样例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// pages/profile/profile.js
Page({
data: {
avatarURL: "",
listCount: 30
},

// 这里针对的是展示数据较多的页面,初始刷新,下拉onPullDownRefresh返回30条数据
// 当用户浏览至底部后,触发onReachBottom返回额外的30条数据

// 监听下拉刷新
onPullDownRefresh() {
console.log("用户进行下拉刷新~");

// 模拟网络请求: 定时器
setTimeout(() => {
this.setData({ listCount: 30 })

// API: 停止下拉刷新
wx.stopPullDownRefresh({
success: (res) => {
console.log("成功停止了下拉刷新", res);
},
fail: (err) => {
console.log("失败停止了下拉刷新", err);
}
})
}, 1000)
},

// 监听页面滚动到底部
onReachBottom() {
console.log("onReachBottom");
this.setData({
listCount: this.data.listCount + 30
})
}
})
1
2
3
4
5
<view class="list">
<block wx:for="{{listCount}}" wx:key="*this">
<view>列表数据:{{ item }}</view>
</block>
</view>

02-下拉刷新

03-下拉刷新

04-上拉刷新

小程序进入场景(场景值)

场景值用来描述用户进入小程序的路径。通俗地说,就是你从哪找到这个小程序的,小程序可以获取到这个值,针对不同的业务场景(场景值),进行相应的处理,以实现更为细致的业务逻辑。相关操作在项目根目录下的app.js中进行,使用onLaunch、onShow函数或者wx.getLaunchOptionSync获取。

个人感觉就像是两个不认识的人——用户A、小程序C,他们都认识小程序B,有一天用户A收到小程序B的推荐认识了小程序C,小程序C为了和用户A相处的更加自然,从小程序B处获取用户A的相关信息。

全局共享数据

通过配置根目录的app.js设置全局的数据globalData,在页面中使用getApp()获取

数据不是响应式,共享的数据通常是一些固定的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// pages/order/order.js
Page({
data: {
userInfo: {}
},

onLoad() {
// 获取共享的数据: App实例中数据
// 1.获取app实例对象
const app = getApp()

// 2.从app实例对象获取数据
const token = app.globalData.token
const userInfo = app.globalData.userInfo
console.log(token, userInfo);

// 3.拿到token目的发送网络请求

// 4.将数据展示到界面上面
// this.data.userInfo = userInfo
this.setData({ userInfo })
console.log(this.data.userInfo);
}
})

登录基本逻辑(app.js)

App框架接口示例代码,由于登录过程比较复杂,这里只做简单说明。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
App({
globalData: {
token: "",
userInfo: {}
},
onLaunch (options) {
// Do something initial when launch.

// 0.从本地获取token/userInfo
const token = wx.getStorageSync("token")
const userInfo = wx.getStorageSync("userInfo")

// 1.进行登录操作(判断逻辑)
if (!token || !userInfo) {
// 将登录成功的数据, 保存到storage
console.log("登录操作");
wx.setStorageSync("token", "kobetoken")
wx.setStorageSync("userInfo", { nickname: "kobe", level: 100 })
}

// 2.将获取到数据保存到globalData中
this.globalData.token = token
this.globalData.userInfo = userInfo

// 3.发送网络请求, 优先请求一些必要的数据
// wx.request({ url: 'url'})
},
onShow (options) {
// Do something when show.
},
onHide () {
// Do something when hide.
},
onError (msg) {
console.log(msg)
}
})

按钮跳转处理逻辑

在首页使用wx:for="{{pages}}"的方式将各个子页面的跳转以按钮的形式呈现出来,方便查看各知识点。

data-xx的使用,后续的传参必须是存在的、可使用的值,xx是个人自定义的名字。

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- home首页 -->
<view class="pages">
<block wx:for="{{pages}}" wx:key="name">
<!-- item是index.js中已定义的值,data-item是个人自定义的名字,data-name、data-id都可以 -->
<button
type="primary"
bindtap="onBtnClick"
data-item="{{item}}"
>
{{ item.name }}
</button>
</block>
</view>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// index.js
Page({
data: {
// path中的 02 是一条错误示范
pages: [
{ name: "01_初体验", path: "/pages/01test/index" },
{ name: "02_页面配置", path: "pages/02_页面配置/index" }
]
},
onBtnClick(event) {
// 1.获取item
const item = event.target.dataset.item

// 2.跳转路径
wx.navigateTo({
url: item.path,
})
}
})

path中不能使用中文,不能使用中文,不能使用中文!以/开头指明路径从根目录开始!

05-path规范

注册加载页面(page)

不要把开发工具固定在任务栏,会造成启动调试器不成功

单个页面(page)的js文件用于发送网络请求、获取数据、同时定义本地固定的数据、绑定页面产生事件的回调函数和刷新滚动操作。onLoad函数在页面加载时发送请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
Page({
data: {
banners: [],
recommends: [],

// 2.作用二: 定义本地固定的数据
counter: 100,

btns: ["red", "blue", "green", "orange"]
},
// 1.作用一: 发送网络请求, 请求数据
onLoad() {
console.log("onLoad");

// 发送网络请求
wx.request({
url: "",
success: (res) => {
const data = res.data.data
const banners = data.banner.list
const recommends = data.recommend.list
this.setData({ banners, recommends })
}
})
},

// 3.绑定wxml中产生事件后的回调函数
onBtn1Click() {
console.log("onBtn1Click");
},
onBtnClick(event) {
console.log("btn click:", event.target.dataset.color);
},

// 4.绑定下拉刷新/达到底部/页面滚动
onPullDownRefresh() {
console.log("onPullDownRefresh");
},
onReachBottom() {
console.log("onReachBottom");
},
onPageScroll(event) {
console.log("onPageScroll:", event);
},

// 生命周期函数:
onShow() {
console.log("onShow");
},
onReady() {
console.log("onReady");
},
onHide() {
console.log("onHide");
},
onUnload() {
console.log("onUnload");
}
})

06-轮播图

1
2
3
4
5
6
7
8
9
10
<view class="banner">
<swiper circular autoplay indicator-dots="{{true}}">
<block wx:for="{{banners}}" wx:key="acm">
<swiper-item>
<!-- image组件默认宽度和高度: 320x240 -->
<image mode="widthFix" src="{{item.image}}"></image>
</swiper-item>
</block>
</swiper>
</view>

常用组件

text

文本组件。其中的user-select参数控制文本是否可选;decode参数控制是否解码,如表示空格的&nbsp&ensp&emspselectable参数控制可选的方案现已废弃。

1
2
3
4
<text>Hello World</text>
<text user-select>{{ message }}</text>
<text user-select="{{true}}">{{ message }}</text>
<text decode>&gt;</text>

08-text组件

button

element组件类似,提供了各种参数控制按钮的样式和功能。其中type参数控制按钮的样式,size参数控制按钮的大小,在开发过程中会经常性地使用open-type参数,满足信息获取的需求。这里需要掌握getUserInfo的处理方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- 获取用户信息 1 -->
<!-- 从 bindgetuserinfo 回调中获取到用户信息 open-type="getUserInfo"时有效 -->
<button
open-type="getUserInfo"
bindgetuserinfo="getUserInfo"
size="mini"
type="primary"
>
用户信息1
</button>

<!-- 获取用户信息 2 -->
<!-- 在组件中绑定一个事件处理函数 -->
<button size="mini" type="primary" bindtap="getUserInfo">用户信息2</button>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Page({
data: {},
getUserInfo(event) {
// 调用API, 获取用户的信息
// 1.早期小程序的API, 基本都是不支持Promise风格
// 2.后期小程序的API, 基本都开发支持Promise风格
wx.getUserProfile({
desc: 'desc',
// success: (res) => {
// console.log(res);
// }
}).then(res => {
console.log(res);
})
},
})

wx.getUserInfo接口已被回收,换成wx.getUserProfile获取用户个人信息。

11-getUserInfo接口失效

12-getUserInfo

view

较为简单,同样可以绑定点击事件。

1
<view bindtap="onViewClick" hover-class="active">我是view组件</view>
1
2
3
4
5
6
7
Page({
...,
onViewClick() {
console.log("onViewClick");
},
...
})

image

mode作为参数控制,图片裁剪、缩放的模式。常用的有:scaleToFill无脑拉伸图片使其铺满元素;aspectFit保持纵横比例缩放图片,较为完整;widthFix宽度不变,高度按原图宽高比自动变化,推荐。

1
2
3
<image src="https://vip2.loli.io/2023/01/25/AxZqRfM1h4TjG2B.png" mode="aspectFit"/>
<image src="https://vip2.loli.io/2023/01/25/AxZqRfM1h4TjG2B.png" mode="widthFix"/>
<image src="https://vip2.loli.io/2023/01/25/AxZqRfM1h4TjG2B.png" mode="heightFix"/>

图片可以和按钮结合,将用户本地的图片展示出来

1
2
<button bindtap="onChooseImage">选择图片</button>
<image class="img" src="{{chooseImageUrl}}" mode="widthFix"/>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// pages/02_common_cpns/index.js
Page({
data: {
chooseImageUrl: "",
},
...,
onChooseImage() {
wx.chooseMedia({
mediaType: "image"
}).then(res => {
const imagePath = res.tempFiles[0].tempFilePath
this.setData({ chooseImageUrl: imagePath })
})
},
...
})

scroll-view

视图容器,规定某个固定高度或宽度的盒子,是通过左右滑动的方式查看内容还是通过上下滑动的方式查看内容。需要注意在对应的wxss文件规定flex

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!-- 上下滚动(y轴) -->
<scroll-view class="container" scroll-y>
<block wx:for="{{viewColors}}" wx:key="*this">
<view class="item" style="background: {{item}};">{{item}}</view>
</block>
</scroll-view>

<!-- 左右滚动(x轴) 允许元素flex 实现多个view在一行 左右滑动查看-->
<scroll-view
class="container scroll-x"
scroll-x
enable-flex
>
<block wx:for="{{viewColors}}" wx:key="*this">
<view class="item" style="background: {{item}};">{{item}}</view>
</block>
</scroll-view>

<!-- 监听事件 -->
<scroll-view
class="container scroll-x"
scroll-x
enable-flex
bindscrolltoupper="onScrollToUpper"
bindscrolltolower="onScrollToLower"
bindscroll="onScroll"
>
<block wx:for="{{viewColors}}" wx:key="*this">
<view class="item" style="background: {{item}};">{{item}}</view>
</block>
</scroll-view>

15-scroll-view滚动

16-scroll-view监听事件

input

注意和vue的v-bind双向绑定的区别。

1
<input type="text" model:value="{{message}}"/>
1
2
3
4
5
6
// index.js
Page({
data: {
message: "Hello, World"
}
})

17-input组件

页面样式

微信小程序的界面样式写法有三种:行内样式、页面样式、全局样式。优先级依次是 行内样式 > 页面样式 > 全局样式。这些都和css类似,不再赘述。

19-wxss支持的选择器

1
2
3
4
5
6
7
8
9
<!-- 1.1.应用全局样式 -->
<!-- 在项目根目录下的 app.wxss 文件-->
<view class="title">learn wxss title</view>

<!-- 1.2.页面中的样式 -->
<view class="message">learn wxss message</view>

<!-- 1.3.行内的样式 -->
<view style="color: blue;">inline style</view>
1
2
3
4
5
6
7
8
9
10
11
/* 单个页面的 index.wxss */
.message {
color: green;
}

/* 根目录 app.wxss */
.title {
font-size: 30px;
font-weight: 700;
color: red;
}

需要注意的是小程序的页面尺寸单位rpx(区别于cssrem)。为了页面根据屏幕宽度进行自适应,规定屏幕宽为 750rpx,如在 iPhone6 上,屏幕宽度为 375 px,共有750个物理像素,则 750 rpx = 375 px = 750 物理像素,1rpx = 0.5px = 1物理像素。

18-页面样式尺寸单位