文章目录
前言
宿主环境是微信客户端给小程序提供的一种环境 。
宿主指的就是微信客户端,也就是官方API里的wx 对象。
宿主环境的作用是什么?
宿主环境会把我们写的各种文件整合到一起,进行解析,然后在微信APP 里显示出我们所看到的样子。
宿主环境可以为小程序提供微信客户端的能力,比如微信扫码,这是普通网页不具备的。
渲染层和逻辑层
双线程下的界面渲染原理
- 在渲染层,宿主环境会把WXML转化成对应的JS对象,也就是虚拟Dom。
- 在逻辑层发生数据变更的时候,我们可以用setData方法把数据从逻辑层传递到渲染层。
- 在渲染层对比虚拟Dom的前后差异,把差异应用在真实Dom上,渲染出正确的UI界面。
WXML变成虚拟DOM后的样子
App
这里说的App 是宿主环境提供的一个 App() 构造器,用于注册一个程序App。
- App() 构造器必须写在项目根目录的app.js里。如:App({…})
- App实例是单例对象,也是一个全局对象,就像网页里的window一样。
- 在其他JS脚本中可以使用宿主环境提供的 getApp() 方法来获取App 实例。如:const app = getApp()
点开微信小程序的一瞬间,微信客户端做了些什么
小程序的后台状态和前台状态
- 后台状态:用户点击小程序右上角关闭按钮,或手机的home 键时,会离开小程序,但小程序并不会被销毁,而是进入后台状态。此时,APP构造器参数里的onHide 方法会被调用。
- 前台状态:用户再次小程序时,微信用户端会唤醒后台状态的微信小程序,微信小程序就进入了前台状态,onShow 方法会被调用。
注意:App的生命周期是由用户操作主动触发的,开发者不能在代码里主动调用
运行js时要留心异步事件
小程序只有一个JSCode 线程,页面有多个。
小程序切换页面时,小程序的逻辑层依旧运行在同一个JsCore线程中。
页面使用了setTimeout或者setInterval的定时器后,跳转到其他页面时,这些定时器并没有被清除,需要开发者自己在页面离开的时候进行清理。
页面
文件构成和路径
一个小程序可以有很多页面,每个页面承载不同的功能,页面之间可以互相跳转。
一个页面是分三部分组成:
界面:WXML、WXSS
配置:JSON
逻辑:JS
页面构造器Page()
页面的js 里的所有代码都是写在Page()构造器里的。
Page构造器接受一个Object参数,在Object中可以绑定数据,监听页面事件。
Page({
data: { text: "This is page data." },
onLoad: function(options) { },
onReady: function() { },
onShow: function() { },
onHide: function() { },
onUnload: function() { },
onPullDownRefresh: function() { },
onReachBottom: function() { },
onShareAppMessage: function () { },
onPageScroll: function() { }
})
页面的生命周期
页面的生命周期首先要考虑三个事件:
- 页面初次加载时:onLoad,在页面没被销毁之前只会触发1次。
- 页面显示时:onShow ,从别的页面返回到当前页面时,都会被调用。
- 页面初次渲染完成时:onReady,在页面没被销毁前只会触发1次,在逻辑层可以和视图层进行交互。
页面显示后,随着用户的操作,还会触发其它的事件:
- 页面不可见时:onHide,wx.navigateTo切换到其他页面、底部tab切换时触发。
- 返回到其它页时:onUnload,wx.redirectTo或wx.navigateBack使当前页面会被微信客户端销毁回收时触发。
页面的用户行为
- 下拉刷新 onPullDownRefresh:监听用户下拉刷新事件,需要在全局或具体页面的json 文件中配置enablePullDownRefresh为true。
- 上拉触底 onReachBottom:监听用户上拉触底事件。可以在app.json的window选项中或页面配置page.json中设置触发距离onReachBottomDistance。在触发距离内滑动期间,本事件只会被触发一次。
- 页面滚动 onPageScroll:监听用户滑动页面事件,参数为 Object,包含 scrollTop 字段,表示页面在垂直方向已滚动的距离(单位px)。
- 用户转发 onShareAppMessage:只有定义了此事件处理函数,右上角菜单才会显示“转发”按钮,在用户点击转发按钮的时候会调用,此事件需要return一个Object,包含title和path两个字段,用于自定义转发内容
页面数据的注意事项
- 用数据驱动视图渲染要用this.setData(),而要用this.data,这不仅无法驱动视图,还会造成数据不一致。
- 由于setData是两个线程间的通信,为了提高性能,每次设置的数据不应超过1024KB 。
- 不要把data中的任意一项的value设为undefined,否则可能会有引起一些不可预料的bug。
页面跳转
页面跳转的方式有很多种:
- 在app.json 中用tabBar 属性设置跳转方式
- 在wxml 页使用导航组件 跳转页面
- 在js 中用路由API跳转
组件
一个小程序的页面是由多个组件组成的。
小程序的宿主环境提供了一系列基础组件。
组件是在WXML模板文件中使用的,写法和HTML 标签相似。如image 组件:
<image mode="scaleToFill" src="img.png"></image>
组件名和属性都是小写,多个单词会以英文横杠 “-” 进行连接。 如:
<kkb-image></kkb-image>
自定义组件
有的时候,宿主环境提供的基础组件无法满足我们的项目需求。这时候我么那就需要自定义组件。
自定义组件的方法:
- 在主项目下建立components 文件夹,在其中建立floatball 文件夹,在此文件夹上右击“新建 Component”,这样就可以建立出json、wxml、wxss、js 四个文件。
- 组件的json中设置 “component”: true
- 组件的wxml、wxss可以正常写。
- 组件的js中的properties 可以接受父组件属性。
- 父组件在调用子组件时要在其json 文件中设置usingComponents,如:
"usingComponents": {
"floatball":"/components/floatball/floatball"
}
父子组件的数据传递
父组件向子组件传递数据:属性
父组件 wxml:
<floatball text="开课吧"></floatball>
子组件 js:
properties: {
text:{type:'string',value:'悬浮球'}
},
子组件向父组件传递数据:事件
在父组件调用子组件时,为其绑定事件,如:
<floatball bind:tapBall=“tapBall"></floatball>
建议onClickBall 的属性名和属性值都写成一样,免得把“在父组件中使用属性值,在子组件中触发属性名”记混了。
在子组件中触发事件的方法是 triggerEvent(eventName, detail),如
this.triggerEvent('tapBall',{tap:true})
api
宿主环境提供了丰富的API,可以很方便调用微信提供的能力。
几乎所有小程序的API都挂载在wx对象底下(除了App/Page等特殊的构造器)。
小程序提供的API按照功能主要分为几大类:网络、媒体、文件、数据缓存、位置、设备、界面、界面节点信息、特殊的开放接口。
API的常见规律
wx.on* 开头的 API 是监听某个事件发生的API接口,接受一个 Callback 函数作为参数。当该事件触发时,会调用 Callback 函数。如wx.onError()
后缀带Sync 的方法是同步的方法。如wx.getSystemInfoSync()
如未特殊约定,多数 API 接口为异步接口 ,都接受一个Object作为参数。如wx.getSystemInfo()
API的Object参数一般由success、fail、complete 来接收请求结果的。如request 接口
wx.get* 开头的API是获取宿主环境数据的接口。如wx.getSystemInfo()
wx.set* 开头的API是写入数据到宿主环境的接口。如wx.setNavigationBarTitle(Object object)
事件
用户在渲染层的行为反馈事件
事件捕捉和事件冒泡
- bind前加上capture- 表示事件捕捉,如capture-bind:tap
- 若不加前缀,bind:tap 和bindtap是一回事。
示例:测试事件冒泡和事件捕捉的差异
在wxml 里建立两个容器对象,里面分别包裹着两个子元素。为容器和子元素添加触摸方法:
<view class="wrapper" bindtap="onTabWrapper">
<view class="rect" bindtap="onTabRect">事件捕捉</view>
</view>
<view class="wrapper" capture-bind:tap="onTabWrapper">
<view class="rect" bindtap="onTabRect">事件冒泡</view>
</view>
js 中的触摸方法:
onTabWrapper(){
console.log('wrapper');
},
onTabRect(){
console.log('rect');
},