-
小程序的双线程模型
- 谁是小程序的宿主环境?微信客户端
- 宿主环境为了执行小程序的各种文件:wxml文件、wxss文件、js文件
-
提供了小程序的双线程模型
小程序双线程模型.png
- 双线程模型
- WXML模板和WXSS央视运行于渲染层,渲染层使用WebView线程渲染(一个程序有多个页面,会使用多个WebView的线程)。
- JS脚本(app.js/home.js等)运行有逻辑层,逻辑层使用JSCore运行JS脚本。
- 这两个线程都会经由微信客户端(Native)进行中转交互。
- 谁是小程序的宿主环境?微信客户端
界面渲染过程
- 初始化渲染
-
wxml等价于一颗DOM树,也可以使用一个JS对象来模拟(虚拟DOM)
WXML和DOM树.jpg -
WXML可以先转成JS对象,再渲染出真正的DOM树
初始化渲染.jpg
-
- 数据发生变化
- 通过setData把msg数据从“Hello World”变成“Goodbye”
- 产生的JS对象对应的节点就会发生变化
- 此时可以对比前后两个JS对象得到变化的部分
- 然后把这个差异应用到原来的DOM树上
- 从而达到更新UI的目的,这就是“数据驱动”的原理
数据改变.jpg
- 通过setData把msg数据从“Hello World”变成“Goodbye”
- 界面渲染整体流程
- 在渲染层,宿主环境会把WXML转化成对应的JS对象;
- 将JS对象再次转成真实DOM树,交由渲染层线程渲染;
- 数据变化时,逻辑层提供最新的变化数据,JS对象发生变化比较进行diff算法对比;
- 将最新变化的内容反映到真实的DOM树中,更新UI;
-
小程序的启动流程
- 官方文档
- 每个小程序都需要在app.js中调用App方法注册小程序实例
-
在注册时,可以绑定对应的生命周期函数,在生命周期函数中,执行对应的代码
小程序启动流程.jpg
-
事件-常见的事件类型
- 什么时候会产生事件呢?
- 小程序需要经常和用户进行某种交互,比如点击界面上的某个按钮或者区域,比如滑动了某个区域,这些交互都会产生各种各样的事件*;
- 事件是如何处理的呢?
- 事件是通过bind/catch这个属性绑定在组件上的(和普通的属性写法很相似,以key=“value”形式);
- key以bind或catch开发,从1.5.0版本开始,可以在bind和catch后加上一个冒号;
- 同时在当前页面的Page构造器中定义对应的事件处理函数tapName,如果没有对应的函数,触发事件时会报错
- 当用户点击该button区域时,达到触发条件生成事件tap,该事件处理函数tapName会被执行,同时还会收到一个事件对象event。
- 某些组件会有自己特性的事件类型,具体查看官方文档
- 比如input有bindinput/bindblur/bindfocus等
- 比如scroll-view有bindscrolltowpper/bindscrolltolower等
- Touchcancle:在某些特定场景下才会触发(比如来电打断等)
- tap事件和longpress事件通常只会触发其中一个
- 什么时候会产生事件呢?
-
组件化开发
-
组件和页面样式细节
组件样式和页面样式.jpg
页面样式课题三.jpg -
给组件传递数据和样式
组件间页面通信.jpg
页面与组件之间传递数据使用properties
向组件传递数据prop.jpg
向组件传递样式.jpg-
定义组件
my-prop
(my-prop.xml)<view class='title titleclass'>{{title}}</view> <view class='content'>我是组件的内容</view>
-
在my-prop.js中定义title的相关属性
Component({ properties: { // title: String title: { type: String, value: '我是默认的标题', observer: function(newVal, oldVal) { console.log(newVal, oldVal) } } }, externalClasses: ['titleclass'] })
observer是记录改变前后的值
externalClasses让外界给我们传递一个不一样的样式,在my-prop中引用之后,页面需要赋予titleclass一个样式,然后这个样式需要在页面的css中赋予属性
```
.red {
color: red;
}.green { color: green; } .blue { color: blue; }
-
在页面(home.xml)中引用组件
my-prop
,并定义title的内容<!-- 3.给自定义组件传递数据/样式 --> <my-prop title="哈哈哈" titleclass="red"/> <my-prop title="呵呵呵" titleclass="green"/> <my-prop titleclass="blue"/>
页面(home.xml)中title定义的“哈哈哈”“呵呵呵”会传递给组件my-prop.xml中{{title}}的插值表达式,此时组件根据页面定义的title展示对应的“哈哈哈”“呵呵呵”
-
- 组件向外传递事件-自定义事件
- 示例:点击组件中的按钮改变页面中的数据
- 自定义组件(my-event.wxml)
<button size='mini' bind:tap="handleIncrement">+1</button>
- 通过
triggerEvent
发射事件,可以传递一个对象(my-event.js)注意:在页面中写方法直接写,在组件中写方法需要在methods中写Component({ methods: { handleIncrement() { // console.log('---------') // 传递一个叫increment的事件,传递参数数组 this.triggerEvent('increment', {name: 'why', age: 18}, {}) } })
- 在页面(home.wxml)中引用组件并监听事件
<!-- 4.组件内部发出事件 --> <view>当前计数: {{counter}}</view> <my-event bind:increment="handleIncrement"/>
- 在页面的逻辑层(home.js)中定义handleIncrement事件,这里相当于组件把事件发射给了页面,此时这个事件就属于页面的逻辑,因此在页面的逻辑层编写。
Page({ data:{ counter:0, }, handleIncrement(event) { console.log('---------', event) this.setData({ counter: this.data.counter + 1 }) }, })
-
组件向外传递事件.jpg
-
获取组件对象的方式
- 在my-sel.wxml中定义一个组件
<view>组件内的计数: {{counter}}</view>
- 在home.wxml中引用组件my-sel,并定义一个按钮绑定点击事件
<!-- 6.直接选中组件修改数据/调用方法 --> <button size='mini' bind:tap="handleIncrementCpn">修改组件内的数据</button> <my-sel class="sel-class" id="sel-id"/>
- 在home.js中获取组件对象
handleIncrementCpn() { // 最终目的: 修改my-sel中的counter // 1.获取组件对象 const my_sel = this.selectComponent('.sel-class') console.log(my_sel) // 2.通过setData修改组件中的数据(不合理,不规范) // my_sel.setData({ // counter: my_sel.data.counter + 20 // }) // 3.通过调用my-sel.js暴露出来的方法对数据进行修改 my_sel.incrementCounter(10) },
- 在my-sel.js中定义方法给页面调用
methods: { incrementCounter(num) { this.setData({ counter: this.data.counter + num }) } }
-
插槽的使用
什么是插槽.jpg
单个插槽的使用.jpg
多个插槽的使用.jpg -
component构造器
component1.jpg
component2.jpg