基础知识

setData同步异步问题

  1. setData在逻辑层的操作是同步,因此this.data中的相关数据会立即更新;
  2. setData在视图层的操作是异步,因此页面渲染可能并不会立即发生。

之所以后者是异步,主要是考虑到将数据从逻辑层发送到视图层的过程中相比直接在逻辑层内操作会花费更多时间也会有更多不确定,于是为保证前端用户体验与减少系统开销,就索性异步了。

但是setData的设计也考虑到有些代码需要在确定setData引起的页面渲染完成后才执行,因此setData其实是有预留渲染完毕后的回调函数的:Page.prototype.setData(Object data, Function callback)

比如下面这个代码片段,就是渲染完毕后才弹出提示对话框,以保证用户体验一致

1
2
3
4
5
6
7
8
9
10
self.setData({
"leader.name": "jack.ma"
},
function() {
wx.showToast({
title: "团队leader已经更改为:"+self.data.leader.name,
icon: "none"
})
}
)

内网穿透

手机访问微信小程序,无法获取pc端的node服务器localhost:3000地址,因为是在内网,而不是公网。因此要想让手机能够访问微信小程序获取数据,需要使用内网穿透工具,推荐使用uTools。https://u.tools/

安装后按Alt+Space可以唤出utools,首先安装内网穿透插件,然后注册、登录。如下开启内网穿透

image-20210330124938042

访问http://music163.cn.utools.club/banner 即可获取首页轮播图的数据

网络请求

  • wx.request()

    报错

    image-20210329231543094

    原因

    • 协议必须是https
    • 一个接口最多配置20个域名(网页端配置),配置http:localhost:3000不行,因为不支持http,同时也不支持localhost,网页端配置的必须是线上服务器地址
    • 并发限制上限为10个
    • 开发过程中需要在详情中如下设置不校验域名
    image-20210329231717492
  • 请求统一封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const BASE_URL = 'http://localhost:3000'
/**
*
* @param {String} url 请求相对地址,不需要带服务器地址,例如/banner
* @param {Object} data 携带数据
* @param {String} method 请求类型'GET' 或者 'POST'
*/
export const WxRequest = (url,data={},method='GET') => {
return new Promise((resolve,reject)=>{
wx.request({
url:BASE_URL+url,
data,
method,
success:(res)=>{
resolve(res.data)
},
fail:(err)=>{
console.error('请求失败',err)
reject(res)
}
})
})
}

数据驱动样式Demo

页面的js代码都在Page函数中,Page函数中的对象类似于rn中类组件的this,使用箭头函数避免this作用域问题

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
import { WxRequest } from "../../utils/request"
// pages/index/index.js
Page({
/**
* 页面的初始数据
*/
data: {
banners:[]
},

/**
* 生命周期函数--监听页面加载
*/
onLoad: async function (options) {
//发送请求获取轮播图数据
const res = await WxRequest('/banner',{type:2})
this.setData({
banners:res.banners
})
console.log(res)
}
})

//列表渲染,rn中是使用map函数,小程序中使用wx-for
//在组件上使用 wx:for 控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。
//数组的当前项的下标变量名默认为 index,数组当前项的变量名默认为 item
//使用 wx:for-item 可以指定数组当前元素的变量名
// 使用wx:for-index 可以指定数组当前下标的变量名
<!-- 轮播图区域 -->
<swiper-item
wx:for="{{banners}}" 绑定数据
wx:key="bannerId" 绑定数据的key,和rn,vue一样,方便页面更新时提高效率
wx:for-index="index" 索引字段名称,通过 index可以获取到循环的索引
wx:for-item="item" 数据字段名称,通过item可以获取到循环的数据
>
<image src="{{item.pic}}" />
</swiper-item>

设置小程序底部tab栏

app.json中配置即可

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
"tabBar": {
"color": "#333",
"selectedColor": "#fa436a",
"backgroundColor": "#ffffff",
"list": [
{
"pagePath": "pages/index/index",
"text": "主页",
"iconPath": "/static/images/tabs/tab-home.png",
"selectedIconPath": "/static/images/tabs/tab-home-current.png"
},
{
"pagePath": "pages/video/video",
"text": "视频",
"iconPath": "/static/images/tabs/select.png",
"selectedIconPath": "/static/images/tabs/selected.png"
},
{
"pagePath": "pages/personal/personal",
"text": "个人中心",
"iconPath": "/static/images/tabs/tab-my.png",
"selectedIconPath": "/static/images/tabs/tab-my-current.png"
}
]
}

事件绑定

事件绑定传参数

1
<input id="phone" data-type="phone" bindinput="handleInput" class="inputText" placeholder="请输入手机号码" value="{{phone}}"/>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 /**
* 手机号码/密码 输入,实现受控组件
* @param {*} e
*/
handleInput:function(e){
//currentTarget与target对象的区别?,这个和事件的委派有关系
//事件委派是基于事件冒泡实现的。
//以前端为例:委派就是给ul绑定一个点击事件,点击ul里面的li时触发li标签的点击事件
//通过e.target可以获取到点击对象,进而获取值

//以微信小程序为例,target不一定指向当前点击的li
//但是currentTarget一定指向这个li

//rn中可以使用高阶函数来传参,小程序中不支持,它bind只支持绑定事件名
//使用id为事件传参表示类型,但是id传参会将数字类型转换成字符类型
// const type = e.currentTarget.id
//使用data-key="value"为事件传参,保留原本类型
const type = e.currentTarget.dataset.type
const {value} = e.detail
this.setData({
[type]:value
})
},
  • 注意:方法之间的公共变量定义在page函数外面
  • bind:tap等同于bindtap
1
2
3
4
5
6
7
<view 
class="contentContainer"
catch:touchstart="handleTouchStart"
catch:touchmove="handleTouchMove"
catch:touchend="handleTouchEnd"
style="transform:{{transform}};transition:{{transition}}"
>
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
// pages/personal/personal.js
//在Page函数外定义变量
let startY = 0; // 手指起始的坐标
let moveY = 0; // 手指移动的坐标
let moveDistance = 0; // 手指移动的距离

Page({

/**
* 页面的初始数据
*/
data: {
transform:'translateY(0rpx)',
transition:''
},

/**
* 滑动开始
* @param {Object} e 事件信息
*/
handleTouchStart: function (e) {
this.setData({
transition:''
})
//touchs表示触摸屏幕的手指数组
startY = e.touches[0].clientY
},

/**
* 滑动中
* @param {*} e
*/
handleTouchMove: function (e) {
moveY = e.touches[0].clientY
moveDistance = moveY - startY
if(moveDistance < 0){
return
}
moveDistance = moveDistance>70?70:moveDistance
this.setData({
transform:`translateY(${moveDistance}rpx)`
})
},

/**
* 滑动结束
* @param {*} e
*/
handleTouchEnd: function (e) {
this.setData({
transform:`translateY(0)rpx)`,
transition:'0.5s linear'
})
}
})

toast

自定义提示方法

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
60
61
62
63
64
65
66
67
68
69
70
71
/**
* 异步Toast提示,自动关闭
* @param {String} title 提示内容
* @param {String} icon 取值为'sucess' 'error' 'loading' 'none',默认为none
* @param {Number} duration 提示的持续时间,默认1500ms
* @param {Boolean} mask 是否显示透明蒙层,防止触摸穿透 ,默认false
* @param {Object} success 成功回调
* @param {Object} fail 失败回调
* @param {Object} complete 完成回调(成功、失败都会执行)
*/
export const showToastAsync = (
title,
icon = "none",
duration = 1500,
mask = false,
success = () => { },
fail = () => { },
complete = () => { }
) => {
wx.showToast({
title,
icon,
duration,
mask,
success,
fail,
complete
})
}

/**
* 异步loading提示,需要调用hideLoadingAsync()关闭
* @param {String} title 提示内容,默认为加载中
* @param {Boolean} mask 是否显示透明蒙层,防止触摸穿透 ,默认false
* @param {Object} success 成功回调
* @param {Object} fail 失败回调
* @param {Object} complete 完成回调(成功、失败都会执行)
*/
export const showLoadingAsync = (
title = "加载中",
mask = false,
success = () => { },
fail = () => { },
complete = () => { }
) => {
wx.showLoading({
title,
mask,
success,
fail,
complete
})
}

/**
* 异步关闭loading提示
* @param {Object} success 成功回调
* @param {Object} fail 失败回调
* @param {Object} complete 完成回调(成功、失败都会执行)
*/
export const hideLoadingAsync = (
success = () => { },
fail = () => { },
complete = () => { }
) =>{
wx.hideLoading({
success,
fail,
complete
})
}

在封装发送请求时,可以在请求发送前显示loading,请求发送后关闭loading,防止用户网络不好等待时间太长或者重复点击

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
import { showToastAsync, showLoadingAsync, hideLoadingAsync } from "../toast/toast"

//本地基路径
export const BASE_URL = 'http://localhost:3000'
//在线基路径,手机没法访问电脑的localhost,因此使用内网穿透
//确定utools的内网穿透开启,并且本地node服务器开启
// export const BASE_URL = 'http://music163.cn.utools.club'
/**
*
* @param {String} url 请求相对地址,不需要带服务器地址,例如/banner
* @param {Object} data 携带数据,默认空对象
* @param {String} method 请求类型'GET' 或者 'POST',默认GET
* @param {Boolean} bShowLoading 请求时是否显示loading提示框,默认true
*/
export const WxRequest = (url, data = {}, method = 'GET',bShowLoading=true) => {
bShowLoading && showLoadingAsync()
return new Promise((resolve, reject) => {
wx.request({
url: BASE_URL + url,
data,
method,
success: (res) => {
resolve(res.data)
},
fail: (err) => {
console.error('请求失败', err)
reject(res)
},
complete: () => {
bShowLoading && hideLoadingAsync()
}
})
})
}

转发分享

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 用户点击右上角分享 / 或者button open-type设置为share也会触发
*/
onShareAppMessage: function (object) {
console.log('开始转发分享',object)
//通过object.from === 'menu' 还是 'button' 可以区分来自谁
const {videoList,activeVideoId} = this.data
return {
title: videoList.find(item => item.vid === activeVideoId).title,
// path:'/pages/video/video',
// imageUrl:'/static/images/nvsheng.jpg'
}
}

title:转发标题

path:转发的页面地址,默认使用当前页面

imageUrl:默认使用当前页面的截图,如果设置,则使用设置的图片

image-20210402114929633

分享到朋友圈

前提:页面js中onShareAppMessage和onShareTimeline回调均存在

可以在onShareTimeline中设置分享到朋友圈的内容

image-20210402115656884

数据缓存封装

微信小程序缓存支持Object类型,也支持数组

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import { showToastAsync } from "../toast/toast"

/**
* 本地存储同步保存
* @param {String} key 键
* @param {*} value 值:任意类型,object类型会自动转换
*/
export const WxSetStorageSync = (key, value) => {
if (typeof value === 'object') {
wx.setStorageSync(key, JSON.stringify(value))
} else {
wx.setStorageSync(key, value)
}

}

/**
* 本地存储异步保存
* @param {String} key 键
* @param {*} value 值:任意类型,object类型会自动转换
* @param {Object} success 成功回调,可选
* @param {Object} fail 失败回调,可选
* @param {Object} complete 完成回调,可选
*/
export const WxSetStorageASync = (
key,
value,
success = () => { },
fail = () => { },
complete = () => { }
) => {
wx.setStorage({
key,
data: typeof value === 'object' ? JSON.stringify(value) : value,
success,
fail,
complete
})
}

/**
* 本地存储同步删除--指定key
* @param {String} key 键
*/
export const WxRemoveStorageSync = (key) => {
wx.removeStorageSync(key)
}

/**
* 本地存储异步删除--指定key
* @param {String} key 键
* @param {Object} success 成功回调,可选
* @param {Object} fail 失败回调,可选
* @param {Object} complete 完成回调,可选
*/
export const WxRemoveStorageASync = (
key,
success = () => { },
fail = () => { },
complete = () => { }
) => {
wx.removeStorage({
key,
success,
fail,
complete
})
}

/**
* 本地存储同步获取--指定key
* @param {String} key 键
*/
export const WxGetStorageSync = (key) => {
try {
const data = wx.getStorageSync(key)
//如果data是String或者Number,那么转换后还是原类型
//如果data是JSON字符产,那么会被转换成Object类型
if(!data){
return ""
}else{
return JSON.parse(data)
}
} catch (e) {
return e
}
}

/**
* 本地存储异步获取--指定key
* @param {String} key 键
* @param {Object} success 成功回调,可选
* @param {Object} fail 失败回调,可选
* @param {Object} complete 完成回调,可选
*/
export const WxGetStorageASync = (
key,
success = () => { },
fail = () => { },
complete = () => { }
) => {
try {
const data = wx.getStorage({
key,
success,
fail,
complete
})
//如果data是String或者Number,那么转换后还是原类型
//如果data是JSON字符串,那么会被转换成Object类型
if(!data){
return ""
}else{
return JSON.parse(data)
}
} catch (e) {
return e
}
}

/**
* 本地存储同步删除--全部,慎用
*/
export const WxClearStorageSync = () => {
try {
wx.clearStorageSync()
} catch (e) {
console.log(e,'本地存储同步清除失败')
showToastAsync('本地存储同步清除失败')
}
}

/**
* 本地存储异步删除--全部,慎用
* @param {Object} success 成功回调,可选
* @param {Object} fail 失败回调,可选
* @param {Object} complete 完成回调,可选
*/
export const WxClearStorageASync = (
success = () => { },
fail = () => { },
complete = () => { }
) => {
try {
wx.clearStorage({
success,
fail,
complete
})
} catch (e) {
console.log(e,'本地存储异步清除失败')
showToastAsync('本地存储异步清除失败')
}
}

小程序中使用npm

1、项目根目录下执行npm init -y初始化package.json

2、开发者工具设置使用npm模块

img

3、下载npm包

npm install 包名

例如 pubsub-js包 ,可以实现页面与页面之间的通信。它是通过自定义事件(订阅与发布)的方式进行的。引入包:import PubSub from ‘pubsub-js’,订阅方:PubSub.subscribe(事件名,事件回调),发布方:PubSub.publish(事件名,提供的数据)
4、构建npm

开发工具 –》 工具 –》 构建npm
会将 node_modules 中的包打包到 miniprogram_npm 中
在这里插入图片描述
注意:执行之后引入的第三方包就会到 miniprogram_npm 中找,如果没找到就会按相对路径查找,没找到就会报错

单例模式

问题:多个视频同时播放

需求:

1、在点击播放的事件中需要找到上一个播放的视频

2、在播放新的视频之前暂停上一个正在播放的视频

实现:

单例模式:需要创建多个对象的场景下,通过一个变量接收,始终保持只有同一个对象,节省内存空间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
handlePlay:function(e){
console.log('点击了播放视频',e)
//分析一下,有三种情况
//1、页面刚打开,用户播放一个视频,进入handlePlay,这时id有值,指向当前点击的视频
// this对象上的id和videoContext都没有值,所有不会执行this.videoContext.pause()
//2、有一个视频正在播放,用户点击其他的视频的播放按钮,进入handlePlay,这时id有值,指向当前点击的视频
// this对象的id指向的是前一个播放视频,和id不同,并且this.videoContext指向前一个视频的对象,这时调用this.videoContext.pause()方法会暂停之前视频的播放
//3、用户点击同一个视频的播放多次,此时this.id和id相同,不会暂停当前视频的播放
const {id} = e.currentTarget
this.id !== id && this.videoContext && this.videoContext.pause()
this.id = e.currentTarget.id
this.videoContext = wx.createVideoContext(id)
this.videoContext.play()
}

自定义模板

杂七杂八

  • navigationBarTextStyle属性只支持hex,不支持red white等字符形式的颜色,color和background-color等一般属性都只是字符串形式的颜色

  • 微信小程序background-image属性不支持本地图片,支持线上地址或者base64

  • 和rn不同,小程序颜色会继承

  • js 7/2结果是小数,不会自动取整

  • js字符串padStart和padEnd方法可用于格式化时间字符串

  • 小程序的里面不允许写js代码(三元表达式除外),只允许写一个this.data中的变量名,和rn不同

  • 小程序颜色如何设置透明度,使用hex透明度,如background-color:#0000005a

  • 推荐使用类选择器

  • WXML中的属性是大小写敏感的

  • currentTarget为当前事件所绑定的组件,而target则是触发该事件的源头组件。

  • 小程序一般使用rpx作为相对屏幕尺寸,类似rn中的pxToDp方法,所有的机型宽度都为750rpx,1px=2rpx

  • wx.showToast()弹出提示框,

  • 和rn中类组件一下,可以使用this.变量名 = 值 给this对象上挂上属性,方便全局共享

  • 页面中可以直接调用,函数中不可以,需要解构this.data

  • 小程序的100vh不包括最下面的tabbar的高度和自身的margin高度, calc函数可以动态计算css的宽高,运算符两次必须加空格,否则无法计算

  • moment-js库可以用来处理时间和日期转换

  • less中如何使用calc函数,https://blog.csdn.net/baidu_39305094/article/details/93178381

  • 文本溢出

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    //单行文本溢出
    text{
    display:block //text是内联元素,overflow:hidden会失效,将其转为块元素
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap
    }

    //多行文本溢出
    text{
    overflow:hidden;
    text-overflow:ellipsis;
    display:-webkit-box;
    -webkit-box-orient:vertical; //设置对其模式:垂直对齐
    -webkit-line-clamp:2; //2行,超出2行则用省略号代替
    }

模板

wx:for

1
2
3
4
5
6
7
<view 
class="scrollItem"
wx:for="{{playList}}"
wx:key="id"
>
<image src="{{item.picUrl}}" />
</view>

wx:if

1
2
3
4
5
6
7
//如果数组有值才会显示播放记录
<scroll-view wx:if="{{playList.length}}"
class="playlistScroll"
enable-flex
croll-x
>
</scroll-view>

路由

wx.switchTab

跳转到tabBar页面,并关闭其他所有非tabBar页面

wx.reLaunch

关闭所有页面,打开到应用内的某个页面

wx.redirectTo

关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面

wx.navigateTo

保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。使用 wx.navigateBack 可以返回到原页面

wx.navigateBack

关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages 获取当前的页面栈,决定需要返回几层

如何返回上一级页面并刷新

如何返回上一级页面-并刷新页面

在使用wx.navigateTo()API 进行跳转时,在子页面中可以通过wx.navigateBack()返回上一级页面的

这个场景在日常开发中,就有不少的

例如:写完微博,发完微博成功后,自动要返回到首页,申请退款时,跳转到申清退款页面等等的

1
2
3
4
5
6
7
8
9
const pages = getCurrentPages(); // 可以获取当前页面栈,上一个页面以及当前页面栈信息
console.log(pages); // 是一个数组,记录了上一个页面与当前页面信息
// 取到上一个页面
const prevPage = pages[pages.length - 2]; // 获取第0个页面,也就是上个页面
console.log(prevPage);
prevPage.onLoad(); // 可以调用上一页面的方法
prevPage.setData({
  name: 'itclanCoder',
});

这个方法非常厉害,而且很有用,当你通过wx.navigateTo(),一层一层跳转到子页面时,使用getCurrentPages方法就可以找到上级,上上级的页面栈信息

它是通过获取到其他页面的原型对象,然后通过小程序原型下的setData方法,对当前对象管理的数据data进行修改

这个方法getCurrentPage方法可以操作页面堆栈页面的数据和方法,可以做到对子(后一)页面对父(上一)页面的数据管理

提示

getCurrentPages()用于获取当前页面栈,数组中第一个元素为首页,最后一个元素为当前页面

不要尝试修改页面栈,会导致路由以及页面状态错误(不要依赖这个方法)

不要在 App.onLaunch 的时候调用 getCurrentPages(),此时 page 还没有生成

路由传参的几种方法

详见链接:https://blog.csdn.net/wzc_coder/article/details/109634775

  • 页面间通过 url 方式传递数据

    • url的方式适合页面间跳转携带参数,多个参数之间使用&符号拼接
    • 此方法有一定的局限性,不适宜传入复杂的数据,例如:数组,对象
    • 适合参数比较少的情况
    • 一般打开新页面在navigateTo方法中使用,如果使用navigateBack,那么在onLoad函数中无法接收到该函数,因为页面已经被打开,onLoad生命周期已经过去,可以用onShow生命周期
  • wx.navigateBack()方法结合getCurrentPages()方法更新数据

  • 使用全局app页面定义的变量实现数据的传递

    • //app.js中onLaunch中定义
      App({
        onLaunch: function() {
          // 定义的全局变量,如token,某些状态等,放在globalData下
          this.globalData = {
            token: 'token',
            url: 'http://coder.itclan.cn/',
            userInfo: 'itclanCoder',
          };
        },
      });
      
      
      //使用页面
      const app = getApp(); // 在另一页面想要使用全局变量处,调用getApp()
      Page({
        // 页面初始化的数据
        data: {
          token: '',
          url: '',
          userInfo: '',
        },
        // 生命周期函数
        onLoad: function(options) {},
       
        onGetGlobal() {
          // 获取全局变量
          const { token, url, userInfo } = app.globalData;
          console.log(token, url, userInfo);
          this.setData({
            token,
            url,
            userInfo,
          });
        },
      });
      
      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
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109

      * 使用本地缓存,跳转路由前一般使用`wx.setStorageSync`:同步设置本地存储某个指定的`key`数据,跳转路由后`wx.getStorageSync`:同步获取本地存储某个指定`key`的数据,数据使用完毕后可以使用wx.removeStorageSync`:从本地存储中同步移除指定的key`

      * 除非用户主动删除或因存储空间原因被系统清理,否则数据都一直可用。单个 `key` 允许存储的最大数据长度为 1MB,所有数据存储上限为 `10MB`,一般可以作为缓存临时一些小的数据,比如用户登录信息之类的
      * 本地缓存的清理时机跟代码包一样,只有在代码包被清理的时候本地缓存才会被清理

      * 使用`eventChannel`向被打开页面传送数据(`wx.navigateTo`高级用法),订阅模式。

      ### 路由触发生命周期

      对于路由的触发方式以及页面生命周期函数如下:

      | 路由方式 | 触发时机 | 路由前页面 | 路由后页面 |
      | :--------- | :----------------------------------------------------------- | :--------- | :----------------- |
      | 初始化 | 小程序打开的第一个页面 | | onLoad, onShow |
      | 打开新页面 | 调用 API [wx.navigateTo](https://developers.weixin.qq.com/miniprogram/dev/api/route/wx.navigateTo.html) 使用组件 [``](https://developers.weixin.qq.com/miniprogram/dev/component/navigator.html) | onHide | onLoad, onShow |
      | 页面重定向 | 调用 API [wx.redirectTo](https://developers.weixin.qq.com/miniprogram/dev/api/route/wx.redirectTo.html) 使用组件 [``](https://developers.weixin.qq.com/miniprogram/dev/component/navigator.html) | onUnload | onLoad, onShow |
      | 页面返回 | 调用 API [wx.navigateBack](https://developers.weixin.qq.com/miniprogram/dev/api/route/wx.navigateBack.html) 使用组件[``](https://developers.weixin.qq.com/miniprogram/dev/component/navigator.html) 用户按左上角返回按钮 | onUnload | onShow |
      | Tab 切换 | 调用 API [wx.switchTab](https://developers.weixin.qq.com/miniprogram/dev/api/route/wx.switchTab.html) 使用组件 [``](https://developers.weixin.qq.com/miniprogram/dev/component/navigator.html) 用户切换 Tab | | 各种情况请参考下表 |
      | 重启动 | 调用 API [wx.reLaunch](https://developers.weixin.qq.com/miniprogram/dev/api/route/wx.reLaunch.html) 使用组件 [``](https://developers.weixin.qq.com/miniprogram/dev/component/navigator.html) | onUnload | onLoad, onShow |

      Tab 切换对应的生命周期(以 A、B 页面为 Tabbar 页面,C 是从 A 页面打开的页面,D 页面是从 C 页面打开的页面为例):

      | 当前页面 | 路由后页面 | 触发的生命周期(按顺序) |
      | :-------------- | :------------ | :------------------------------------------------- |
      | A | A | Nothing happend |
      | A | B | A.onHide(), B.onLoad(), B.onShow() |
      | A | B(再次打开) | A.onHide(), B.onShow() |
      | C | A | C.onUnload(), A.onShow() |
      | C | B | C.onUnload(), B.onLoad(), B.onShow() |
      | D | B | D.onUnload(), C.onUnload(), B.onLoad(), B.onShow() |
      | D(从转发进入) | A | D.onUnload(), A.onLoad(), A.onShow() |
      | D(从转发进入) | B | D.onUnload(), B.onLoad(), B.onShow() |

      **Tips**:

      - `navigateTo`, `redirectTo` 只能打开非 tabBar 页面。
      - `switchTab` 只能打开 tabBar 页面。
      - `reLaunch` 可以打开任意页面。
      - 页面底部的 tabBar 由页面决定,即只要是定义为 tabBar 的页面,底部都有 tabBar。
      - 调用页面路由带的参数可以在目标页面的`onLoad`中获取。

      ## 组件介绍

      ### 自定义组件components

      <img src="https://gitee.com/chen_hexi/image-source/raw/master/img/20210514151331.png" alt="image-20210330100132753" style="zoom: 50%;" />

      组件属性定义

      <img src="https://gitee.com/chen_hexi/image-source/raw/master/img/20210514151335.png" alt="image-20210330104740293" style="zoom:50%;" />

      组件html中使用属性

      <img src="https://gitee.com/chen_hexi/image-source/raw/master/img/20210514151340.png" alt="image-20210330105056696" style="zoom:50%;" />

      **在要使用这个组件的page的json文件中**

      <img src="https://gitee.com/chen_hexi/image-source/raw/master/img/20210514151343.png" alt="image-20210330104939679" style="zoom:50%;" />

      在page中使用

      ![image-20210330105026715](https://gitee.com/chen_hexi/image-source/raw/master/img/20210514151347.png)

      ### view

      类似div和rn中的View,占位标签

      类似于rn中view和scrllview容器集合,小程序中垂直方向内容溢出会自动出现滚动条

      ### text

      文本标签,包裹文字,不是必须要有

      rn中不允许文字单独显示,必须要包裹在Text标签中,微信小程序中不是必须要有text标签包裹

      注意:text标签中换行将被显示在界面上

      ### swiper

      indicator-dots 是否显示底部圆点

      indicator-color 圆点未被选中的颜色

      indicator-active-color 圆点选中的颜色

      next-margin 设置是否让下一个轮播的区域在屏幕中提前显示,提醒用户该组件可以轮播



      ```html
      <!-- 轮播图区域 -->
      <swiper class="swiperContainer" indicator-dots="true" indicator-color="#ffffff" indicator-active-color="#ea4a2b">
      <swiper-item>
      <image src="../../static/images/nvsheng.jpg" />
      </swiper-item>
      <swiper-item>
      <image src="../../static/images/nvsheng.jpg" />
      </swiper-item>
      <swiper-item>
      <image src="../../static/images/nvsheng.jpg" />
      </swiper-item>
      <swiper-item>
      <image src="../../static/images/nvsheng.jpg" />
      </swiper-item>
      <swiper-item>
      <image src="../../static/images/nvsheng.jpg" />
      </swiper-item>
      </swiper>

image

<image src="../../static/images/nvsheng.jpg" />

scroll-view

可滚动视图区域,使用竖向滚动时,需要给它设置一个固定高度,通过WXSS设置height,组件属性的长度单位默认为px

属性 类型 默认值 必填 说明 最低版本
scroll-into-view string 值应为某子元素id(id不能以数字开头)。设置哪个方向可滚动,则在哪个方向滚动到该元素 1.0.0
scroll-with-animation boolean false 在设置滚动条位置时使用动画过渡 1.0.0
scroll-x boolean false 允许横向滚动 1.0.0
scroll-y boolean false 允许纵向滚动 1.0.0
enable-flex boolean false 启用 flexbox 布局。开启后,当前节点声明了 display: flex 就会成为 flex container,并作用于其孩子节点。 2.7.3
refresher-enabled boolean false 开启自定义下拉刷新 2.10.1
refresher-triggered boolean false 设置当前下拉刷新状态,true 表示下拉刷新已经被触发,false 表示下拉刷新未被触发 2.10.1
bindrefresherrefresh eventhandle 自定义下拉刷新被触发 2.10.1

如何设置横向滚动,并且不设置高度,那么它的高度会很高,默认时内部元素竖向排列的高度,给scroll-view设置一个高度即可

scroll-into-view结合scroll-with-animation可以实现点击tab永远在最前并且移动过渡效果,注意scroll-into-view应该为某子元素id,不能以数字开头

refresher-enabled结合refresher-triggered和bindrefresherrefresh属性可以实现scroll-view下拉刷新

注意区分滚动条上拉加载、下拉刷新与页面的下拉onPullDownRefresh和上拉触底onReachBottom的区别,同时,要触发onPullDownRefresh,必须在配置项中设置enablePullDownRefresh为true

video

1
2
3
4
5
6
7
8
<video 
bind:play="handlePlay" 绑定视频播放事件
id="{{item.vid}}"
src="{{item.urlInfo.url}}" 视频地址
poster="{{item.coverUrl}}" 视频封面的图片网络资源地址
wx:if="{{activeVideoId === item.vid}}" 条件语句
object-fit="cover" 视频内容覆盖容器
/>

button

open-type属性可用来实现特殊的功能,例如转发分享等

input

placeholder-class和placeholder-style可以用来设置placeholder的样式

注意区分input的change和input事件区别

对于用户的操作及时响应是非常优秀的体验,有时候在点击button按钮处理更耗时的操作时,我们也会使用button组件的loading属性,在按钮的文字前边出现一个Loading,让用户明确的感觉到,这个操作会比较耗时,需要等待一小段时间。

showModal弹出模态框

showToast 弹出提示框

showLoading 弹出加载框

其他

vscode环境搭建

  • 打开微信开发者工具,设置预编译窗口悬浮

image-20210329204505171

  • vscode安装插件支持微信小程序开发 wxml minapp、wechat-snippet EasyWXLESS(支持将微信LESS文件自动转换为WXSS微信样式文件),同时EasyLess要在当前工作区(小程序环境)内禁用,这样省得一个less编译出css和wxss两种文件,小程序开发只要一种wxss就好

引入iconfont

在官网图标选择图标添加到项目,然后选择fontclass,生成在线代码,但是这个是css格式的,小程序不支持css,需要将这个代码打开,复制css代码并保存到项目中新建的iconfont.wxss文件中,可以理解为存储的是选择图标的离线数据。如果在线项目图标库更新,需要重新生成css代码并拷贝到iconfont.wxss文件中

image-20210329215423807

image-20210329215549131

image-20210329215614934