小程序开发文档-知识点小记(1)
小程序技术发展史
JS-SDK是对之前的WeixinJSBrige的一个包装,以及新能力的释放,并且由对内开放转为了对所有开发者开放;
微信Web资源离线存储是面向Web开发者提供的基于微信内的Web加速方案。
通过使用微信离线存储,Web开发者可借助微信提供的资源存储能力,直接从微信本地加载Web资源而不需要再从服务端拉取,从而减少网页加载时间,为微信用户提供更优质的网页浏览体验,每个公众号下所有WebApp累计最多可缓存5M的资源。
影响web体验的问题: 1 白屏 2 缺少操作的反馈
快速的加载
更强大的能力
原生的体验
易用且安全的微信数据开放
高效和简单的开发
小程序与普通网页开发的区别
网页开发渲染线程和脚本线程是互斥的,这也是为什么长时间的脚本运行可能会导致页面失去响应,而在小程序总,二者是分开的,分别运行在不同的线程中。网页开发者可以使用到各种浏览器暴露出来的DOM API,进行DOM选中和操作。而如上文所述,小程序的逻辑层和渲染层是分开的,逻辑层运行的JSCore中,并没有一个完成的浏览器对象,因而缺少相关的DOM API和BOM API;例如JQuery Zepto等,在小程序中是无法运行的。同时JSCore的环境同NodeJS环境也是不尽相同的,所以一些NPM的包在小程序中也是无法运行的。
JSON 配置
JSON文件在小程序代码中扮演静态配置的作用,在小程序运行之前就决定了小程序一些表现,需要注意的是小程序是无法在运行过程中动态更新JSON配置文件从而发生对应的变化的。
WXML 模板
WXML 是WeiXin Markup Language
要求标签必须是严格闭合的,没有闭合将会导致编译错误。WXML的属性是大小写敏感的。
wx:if是一个控制属性,需要将它添加到一个标签上,如果要一次性判断多个组件标签,可以使用一个<block/>标签将多个组件包装起来,并在上边使用wx:if控制属性。
列表渲染 wx:for
默认数组的当前项的下标变量名默认为index,数组当前项的变量名默认为item。
使用wx:for-item 指定数组当前元素的变量名,使用wx:for-index指定数组当前下标的变量名
类似block wx:if ,也可以将wx:for 用在<block/>标签上,以渲染一个包含多节点的结构块。
如果列表中项目的位置会改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态,需要使用wx:key来指定列表中项目的唯一的标识符。
wx:key的值以两种形式提供:
1字符串,代表在for循环的array中item的某个property,该property的值需要是列表中唯一的字符串或数字,且不能动态改变。
2 保留关键字this代表在for循环中的item本身,这种表示需要item本身是一个唯一的字符串或者数字
当数据改变触发渲染层重新渲染的时候,会校正带有key的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。
WXML提供模板,可以在模板中定义代码片段,然后在不同的地方调用。使用name属性,作为模板的名字。然后在<template/>内定义代码片段
使用is属性,声明需要的使用的模板,然后将模板所需要的data传入
wxml提供两种文件引用方式import和include。
import可以在该文件中使用目标文件定义的template:
需要注意的是import有作用于的概念,即只会import目标文件中定义的template,而不会import目标文件中import的template,简而言之就是import不具有递归的特性。
include可以将目标文件中除了<template/><wxs/>外的整个代码引入,相当于是拷贝到include位置
共同属性
所有wxml标签都支持的属性称之为共同属性:
id class style hidden data-* bind*/catch*
WXSS WeiXin Style Sheets
项目公共样式
其他样式
在小程序开发中国,开发者不需要像Web开发那样去优化样式文件的请求数量,只需要考虑代码的组织即可。样式文件最终会被编译优化。
渲染层和逻辑层
小程序的运行环境分为渲染层和逻辑层,WXML WXSS 工作在渲染层,js运行在逻辑层。
渲染层和数据有关
逻辑层负责生产、处理数据
逻辑层通过Page实例的setData方法传递数据到渲染层
通信模型
小程序的渲染层和逻辑层分别由2个线程管理:渲染层的界面使用了WebView进行渲染;逻辑层采用JsCore线程运行Js脚本,一个小程序存在多个界面,所以渲染层存在多个WebView线程,这两个线程的通信会经由微信客户端做中转,逻辑层发送网络请求也经由Native转发
数据驱动
可以让状态和视图绑定在一起
程序与页面
程序的生命周期和打开场景
初次进入小程序的时候,微信客户端初始化好宿主环境,同时从网络下载或者从本地缓存中拿到小程序的代码包,把它注入到宿主环境,初始化完毕后,微信客户端就会给App实例派发onLaunch事件,App构造器参数所定义的onLaunch方法会被调用。
进入小程序之后,用户可以点击右上角的关闭,或者按手机设备的Home键离开小程序,此时小程序并没有被直接销毁,我们把这种情况称为‘小程序进入后台状态’,App构造器参数所定义的onHide方法会被调用。
当再次回到微信或者再次打开小程序时,微信客户端会把‘后台’的小程序唤醒,我们把这种情况称为‘小程序进入前台状态’,App构造器的onShow方法会被调用。
我们可以看到,App的生命周期是由微信客户端根据用户操作主动触发的,为了避免程序上的混乱,我们不应该从其他代码里主动调用App实例的生命周期函数。
在微信客户端中打开小程序有很多途径:从群聊会话里打开,从小程序列表中打开,通过微信扫一扫二维码打开,从另外一个小程序打开当前小程序等,针对不同路径的打开方式,小程序有时需要做不同的业务处理,所以微信客户端会把打开方式带给onLaunch和onShow的调用参数options,
小程序全局数据
小程序的js脚本是运行在JSCore的线程中,小程序的每个页面各自有一个WebView线程进行渲染,所以小程序切换页面时,小程序逻辑层的JS脚本运行上下文依旧在同一个JSCore线程中。
App实例是单例的,因此不同的页面直接可以通过App实例下的属性来共享数据。App构造器可以传递其他参数作为全局属性以达到全局共享数据的目的。
与此同时,我们要特别留意一点,所有页面的脚本逻辑都跑在同一个JsCore线程,页面使用setTimeout或者setInterval的定时器,然后跳转到其他页面时,这些定时器并没有被清除,需要开发者自己在页面离开的时候进行清理。
页面
页面构造器Page()
生命周期函数:
onLoad 监听页面加载,触发时机早于onShow和onReady
onShow 监听页面显示,触发事件早于onReady
onReady 监听页面初次渲染完成
onHide 监听页面隐藏
onUnload 监听页面卸载
页面的用户行为:
onPullDownRefresh 监听用户下拉动作
onReachBottom 页面上拉触底事件的处理函数
onShareAppMessage 用户点击右上角转发
onPageScroll 页面滚动触发事件的处理函数
页面的生命周期和打开参数
页面初次加载的时候,微信客户端就会给Page实例派发onLoad事件,Page构造器参数所定义的onLoad方法会被调用,onLoad页面没被销毁之前只会触发一次,在onLoad的回调中,可以获取当前页面所调用的打开参数option,页面显示之后,Page构造器参数所定义的onShow方法会被调用,一般从别的页面返回当当前页面时,当前页的onShow方法会被调用。在页面初次渲染完成时,Page构造器参数所定义的onReady方法会被调用,onReady在页面没被销毁前只会触发一次,onReady触发时,表示页面已经准备妥当,在逻辑层就可以和视图层进行交互了。
页面不可见时,Page构造器参数所定义的onHide方法会被调用,这种情况会在使用wx.navigateTo切换到其他页面
底部tab切换时触发。
当前页面使用wx.redirectTo或navigateBack返回到其他页面,当前页面会被微信客户端销毁回收,onUnload方法会被调用。
我们可以看到,Page的生命周期是由微信客户端根据用户操作主动触发的,为了避免程序上的混乱,我们不应该在其他代码中主动调用Page的生命周期函数。
页面的数据
宿主环境所提供的的Page实例的原型中有setData函数,我们可以在Page实例下的方法调用this.setData把数据传递给渲染层,从而达到更新界面的目的。由于小程序的渲染层和逻辑层分别的两个线程中运行,所以setData传递数据实际是一个异步的过程,所以setData的第二个参数是一个callback回调,在这次setData对界面渲染完毕后触发。
setData其一般调用格式是setData(data,callback),其中data是由多个key:value构成的Object对象。
实际在开发的时候,页面的data数据会涉及相当多的字段,你并不需要每次都将整个data字段重新设置一遍,你只需要把改变的值进行设置即可,宿主环境会自动把新改动的字段合并到渲染层对应的字段中。
我们只要保持一个原则就可以提高小程序的渲染性能:每次只设置需要改变的最小单位数据。
注意:
1 直接修改Page实例的this.data而不调用this.setData是无法改变页面的状态的,这回造成数据不一致。
2 由于setData是需要两个线程的一些通信消耗,为了提高性能,每次设置的数据不应超过1024KB;
3 不要把data中的任意一项的value设为undefined,否则可能会引起一些不可预料的bug
页面的用户行为
小程序宿主环境提供可四个和页面相关的用户行为回调:
1 下拉刷新onPullDownRefresh
监听用户下拉刷新事件,需要在app.json的window选项中或页面配置page.json中设置enablePullDownRefresh为true。当处理完数据刷新后,wx.stopPullDownRefresh可以停止当前页面的下拉刷新。
2 上拉触底onReachBottom
监听用户上拉触底事件。可以在app.json的window选项中或页面配置page.json中设置触发距离onReachBottomDistance,在触发距离内滑动期间,本事件只会被触发一次。
3 页面滚动 onPageScroll
监听用户滑动页面事件,参数为Object,包含scrollTop字段,表示页面在垂直方向已滚动的距离(单位px)
4 用户转发onShareAppMessgae
只有定义了此事件处理函数,右上角菜单才会显示‘转发’按钮,在用户点击转发按钮的时候会调用,此事件需要return一个Object,包含title和path两个字段,用于自定义转发内容。
页面跳转和路由
一个小程序拥有多个页面,我们可以通过wx.navigateTo推入一个新的页面,在首页使用2次wx.navigateTo后,页面层级会有3层,我们把这样的一个页面层级称为页面栈。
小程序宿主环境限制了这个页面栈的最大层级是10层,
wx.navigateTo()可以往当前页面找推入一个。
navigateBack 可以退出当前页面栈的最顶上页面
redirectTo 是替换当前页,当页面栈到达10层没法新增的时候,往往就是使用redirectTo这个API进行页面跳转
switchTo 此时原来页面栈会被清空(除了已经声明为Tabbar的页面其他的页面都会被销毁)
navigateTo redirectTo 只能打开非TabBar页面,switchTab只能打开Tabbar页面
reLaunch({url:'pageH'}) 重启小程序,并且打开pageH,此时页面栈为[pageH]