[TOC]
小程序开发经验积累
setData动态属性写法
this.setData({
redis: a,
[`redis2[0]`]: a
});
小程序setData时,数据没更新
由于小程序不支持将 data 中任何一项的 value 设为 undefined ,在 setState 的时候也请避免这么用。你可以使用 null 来替代。
setData有的值之前有值,重新set为undefined时,会导致页面不更新 解决办法 判断是undefined时,将值设为null
key ? key : null
小程序用get请求传数组时,取到的值不正确
request({
data: {
list: ['11','sss']
}
})
应改为
request({
data: {
list: ['11','sss'].join(','gst)
}
})
js判断小程序环境
小程序内置web-view引入页面时,
官方文档建议通过 window.__wxjs_environment === 'miniprogram' 判断小程序环境。经测试在安卓有些设备上会失效。
wx.miniProgram.getEnv也会失效
wx.miniProgram.getEnv(function(res) {
if (res.miniProgram) {
// 走在小程序的逻辑
alert("小程序环境" + window.__wxjs_environment);
}
});
解决方案
通过userAgent 判断
const isMiniProgram = /miniProgram/i.test(navigator.userAgent.toLowerCase());
UserAgent 详解
通过UA来判断不同的设备或浏览器是开发者最常用的方法
在控制台打印navigator.userAgent查看
Android 系统下的微信 User Agent
Mozilla/5.0 (Linux; Android 7.1.1; MI 6 Build/NMF26X; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/6.2 TBS/043807 Mobile Safari/537.36 MicroMessenger/6.6.1.1220(0x26060135) NetType/WIFI Language/zh_CN
iPhone 系统下的微信 User Agent
Mozilla/5.0 (iPhone; CPU iPhone OS 9_3_2 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Mobile/13F69 MicroMessenger/6.6.1 NetType/4G Language/zh_CN
微信内置浏览器与小程序中的User Agent 对比
// 安卓系统中小程序 User Agent
Mozilla/5.0 (Linux; Android 7.1.1; MI 6 Build/NMF26X; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/6.2 TBS/043807 Mobile Safari/537.36 MicroMessenger/6.6.1.1220(0x26060135) NetType/4G Language/zh_CN MicroMessenger/6.6.1.1220(0x26060135) NetType/4G Language/zh_CN miniProgram
// 安卓系统中微信内置浏览器 User Agent
Mozilla/5.0 (Linux; Android 7.1.1; MI 6 Build/NMF26X; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.132 MQQBrowser/6.2 TBS/043807 Mobile Safari/537.36 MicroMessenger/6.6.1.1220(0x26060135) NetType/4G Language/zh_CN
以上字符串为MI6安卓设备中获得。可以看出微信小程的UA和微信内置浏览器UA是不同的,特别是最后的'miniProgram'字符串。而在iPhone系统设备中UA是一致的, 小程序和微信内置浏览器UA没有区别。
UA检测和判断方法
if (/MicroMessenger/i.test(navigator.userAgent)) {
console.log('当前为微信访问');
}
开源工具推荐
目前生产环境使用该库来判断移动,Android,iOS等环境。
小程序里一定要用https, 无法访问http
解决办法:配置Charles www.cnblogs.com/xcsn/p/7538…
小程序生命周期
onload ----> onshow ----> onready 即使在onload阶段发生跳转,后面的流程还是会继续执行。
原则上onload 只会执行一次,onshow每次页面显示才会显示。
所有页面onload阶段的options是从跳转的page url后跟的参数取到的。
组件button样式
button去掉边框(适用于百度小程序)
.btn{
backgrond:none;
}
.btn::after{
border: none;
}
button 阻止冒泡
有的button 设置了默认操作例如open-type='share' 点击以后父容器有click事件,也会触发。
解决办法: 在button绑定一个方法 return false;
开发框架
用过wepy各种坑,弃坑
优化
微信小程序开发资源汇总
好的目录结构
├── README.md // 说明文档
├── dist // 编译后的代码,用小程序开发工具打开此文件夹
├── mock.js // 模拟数据的文件
├── package-lock.json
├── package.json
├── project.config.json // 项目配置文件
├── src // 项目代码都在这个文件夹下
│ ├── app.js // 等同于小程序根目录下的app.js
│ ├── app.json // 等同于小程序根目录下的app.json
│ ├── app.wxss // 等同于小程序根目录下的app.wxss
│ ├── assets // 项目中使用到的静态资源
│ │ └── images
│ │ ├── example
│ │ └── tab
│ ├── components // 公用的组件
│ ├── page // 存放小程序的各个页面文件
│ │ ├── example // example 页面
│ │ │ ├── components // example页面中的组件
│ │ │ ├── index.js
│ │ │ ├── index.json
│ │ │ ├── index.wxml
│ │ │ ├── index.wxss
│ │ │ ├── services // example页面中接口
│ │ │ ├── template // example页面中的模板
│ │ │ └── wxs // example页面中的wxs文件
│ │ ├── globalStore.js // 全局共享的数据
│ │ └── test
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ ├── template // 公用的模板
│ └── utils // 公用的方法或工具
│ ├── config.js // 全局的一些配置信息
│ ├── create.js // 状态管理插件
│ ├── mitt.js // 状态管理插件
│ ├── obaa.js // 状态管理插件
│ ├── util.js // 公用方法
│ ├── wxRequest.js // 封装的小程序请求数据方法
│ └── wxapi.js // 对小程序api进行Promise封装
└── weapp.config.js // 对脚手架的配置文件
小程序的双线程结构
与传统的浏览器Web页面最大区别在于,小程序的是基于 双线程 模型的, 在这种架构中,小程序的渲染层使用 WebView 作为渲染载体,而逻辑层则由独立的 JsCore 线程运行 JS 脚本,双方并不具备数据直接共享的通道,因此渲染层和逻辑层的通信要由 Native 的 JSBrigde 做中转。
小程序更新视图数据的通信流程
每当小程序视图数据需要更新时,逻辑层会调用小程序宿主环境提供的 setData 方法将数据从逻辑层传递到视图层,经过一系列渲染步骤之后完成UI视图更新。完整的通信流程如下:
-
小程序逻辑层调用宿主环境的 setData 方法。
-
逻辑层执行 JSON.stringify 将待传输数据转换成字符串并拼接到特定的JS脚本,并通过evaluateJavascript 执行脚本将数据传输到渲染层。
-
渲染层接收到后, WebView JS 线程会对脚本进行编译,得到待更新数据后进入渲染队列等待 WebView 线程空闲时进行页面渲染。
-
ebView 线程开始执行渲染时,待更新数据会合并到视图层保留的原始 data 数据,并将新数据套用在WXML片段中得到新的虚拟节点树。 经过新虚拟节点树与当前节点树的 diff 对比,将差异部分更新到UI视图。同时,将新的节点树替换旧节点树,用于下一次重渲染。
引发渲染性能问题的原因
- setData传递大量新数据 数据的传输会经历跨线程传输和脚本编译的过程,当数据量过大,会增加脚本编译的执行时间,占用 WebView JS 线程。
- 频繁的执行setData操作 频繁的执行 setData 会让 WebView JS 线程一直忙碌于脚本的编译、节点树的对比计算和页面渲染。
- 过多的页面节点数 页面初始渲染时,渲染树的构建、计算节点几何信息以及绘制节点到屏幕的时间开销都跟页面节点数量成正相关关系,页面节点数量越多,渲染耗时越长。 每次执行 setData 更新视图,WebView JS 线程都要遍历节点树计算新旧节点数差异部分。当页面节点数量越多,计算的时间开销越大,减少节点树节点数量可以有效降低重渲染的时间开销。
渲染性能优化
setData优化
-
减少 setData 数据传输量
仅传输视图层使用到的数据,其他 JS 环境用到的数据存放到 data 对象外。
合理利用局部更新。
setData 支持使用 数据路径 的方式对对象的局部字段进行更新。
// 只更新需要更新的数据!!! // 后台获取列表数据 const list = requestSync(); // 更新整个列表----错误❌ this.setData({ list }); // 局部更新列表---√ this.setData({ 'list[0].src': list[0].src }); -
降低 setData 执行频率
在不影响业务流程的前提下,将多个 setData 调用合并执行,减少线程间通信频次。
-
善用自定义组件
小程序自定义组件的实现是由小程序官方设计的 Exparser 框架所支持,框架实现的自定义组件的组件模型与 Web Components 标准的 Shadow DOM 相似.
在页面引用自定义组件后,当初始化页面时,Exparser 会在创建页面实例的同时,也会根据自定义组件的注册信息进行组件实例化,然后根据组件自带的 data 数据和组件WXML,构造出独立的 Shadow Tree ,并追加到页面 Composed Tree 。创建出来的 Shadow Tree 拥有着自己独立的逻辑空间、数据、样式环境及setData调用.
基于自定义组件的 Shadow DOM 模型设计,我们可以将页面中一些需要高频执行 setData 更新的功能模块(如倒计时、进度条等)封装成自定义组件嵌入到页面中。
当这些自定义组件视图需要更新时,执行的是组件自己的 setData ,新旧节点树的对比计算和渲染树的更新都只限于组件内有限的节点数量,有效降低渲染时间开销。
当然,并不是使用自定义组件越多会越好,页面每新增一个自定义组件, Exparser 需要多管理一个组件实例,内存消耗会更大,当内存占用上升到一定程度,有可能导致 iOS 将部分 WKWebView 回收,安卓机体验会变得更加卡顿。因此要合理的使用自定义组件,同时页面设计也要注意不滥用标签。
总结
小程序双线程架构决定了数据通信优化会是性能优化中一个比较重要的点。 而上述提到的几个优化建议只是优化渲染性能中的一部分,要想让你的页面体验变得更加丝滑, 就要熟悉小程序框架的底层原理,根据小程序框架的特点,编写出“合身”的前端代码。
小程序传递url里有特殊字符,比如+
用 encodeURIComponent(JSON.stringify(address)),方式传递,在接收时,不用decode,直接获取即可
如果不用encode,获取到的值里+会丢失
小程序textarea适配问题
在页面中用到了textarea,测试发现的问题:
- 高度无法自适应
- 删除时,光标会自动到第一个
- 有的手机上多行展示不自动换行
解决办法:
挨个排除每个属性,看是哪个属性影响导致的。
发现 auto-height 导致的问题,去掉auto-height,采用css设置height为固定高度,解决问题