目录
什么是生命周期函数
WXS脚本
编辑
与 JavaScript 不同
纯数据字段
组件生命周期
定义生命周期方法
代码示例
组件所在页面的生命周期
代码示例
插槽
什么是插槽
启用多插槽
编辑 定义多插槽
组件通信
组件间通信
监听事件
触发事件
获取组件实例
自定义的组件实例获取结果
Behaviors
使用npm包
Vant组件库
使用 Vant 组件
API Promise化
全局数据共享
Store中的成员绑定到页面中:
Store中的成员绑定到组件中:
在组件中使用Store中的成员
分包
什么是分包
分包的好处
什么是生命周期函数
生命周期函数:是由小程序框架提供的内置函数,会伴随着生命周期,自动按次序执行。
生命周期函数的作用:允许程序员在特定的时间点,执行某些特定的操作。例如,页面刚加载的时候,可以在 onLoad 生命周期函数中初始化页面的数据。
注意:生命周期强调的是时间段,生命周期函数强调的是时间点。
WXS脚本
2.外联wxs脚本
与 JavaScript 不同
为了降低 wxs(WeiXin Script)的学习成本, wxs 语言在设计时借大量鉴了 JavaScript 的语法。但是本质上, wxs 和 JavaScript 是完全不同的两种语言
不能作为组件的事件回调
wxs 典型的应用场景就是“过滤器”,经常配合 Mustache 语法进行使用, 但是,在 wxs 中定义的函数不能作为组件的事件回调函数。例如,下面的用法是错误的:
隔离性指的是 wxs 的运行环境和其他 JavaScript 代码是隔离的。体现在如下两方面:
① wxs 不能调用 js 中定义的函数
② wxs 不能调用小程序提供的 API
性能好
⚫ 在 iOS 设备上,小程序内的 WXS 会比 JavaScript 代码快 2 ~ 20 倍
⚫ 在 android 设备上,二者的运行效率无差异
纯数据字段
通配符监听对象的属性RGB,这里面的rgb.r,rgb.g,rgb.b都没有用于界面的渲染
组件生命周期
组件的生命周期,指的是组件自身的一些函数,这些函数在特殊的时间点或遇到一些特殊的框架事件时被自动触发。
其中,最重要的生命周期是 created
attached
detached
,包含一个组件实例生命流程的最主要时间点。
- 组件实例刚刚被创建好时,
created
生命周期被触发。此时,组件数据this.data
就是在Component
构造器中定义的数据data
。 此时还不能调用setData
。 通常情况下,这个生命周期只应该用于给组件this
添加一些自定义属性字段。 - 在组件完全初始化完毕、进入页面节点树后,
attached
生命周期被触发。此时,this.data
已被初始化为组件的当前值。这个生命周期很有用,绝大多数初始化工作可以在这个时机进行。 - 在组件离开页面节点树后,
detached
生命周期被触发。退出一个页面时,如果组件还在页面节点树中,则detached
会被触发。
定义生命周期方法
生命周期方法可以直接定义在 Component
构造器的第一级参数中。
自小程序基础库版本 2.2.3 起,组件的的生命周期也可以在 lifetimes
字段内进行声明(这是推荐的方式,其优先级最高)。
代码示例
Component({lifetimes: {attached: function() {// 在组件实例进入页面节点树时执行},detached: function() {// 在组件实例被从页面节点树移除时执行},},// 以下是旧式的定义方式,可以保持对 <2.2.3 版本基础库的兼容attached: function() {// 在组件实例进入页面节点树时执行},detached: function() {// 在组件实例被从页面节点树移除时执行},// ...
})
在 behaviors 中也可以编写生命周期方法,同时不会与其他 behaviors 中的同名生命周期相互覆盖。但要注意,如果一个组件多次直接或间接引用同一个 behavior ,这个 behavior 中的生命周期函数在一个执行时机内只会执行一次。
可用的全部生命周期如下表所示。
生命周期 | 参数 | 描述 | 最低版本 |
---|---|---|---|
created | 无 | 在组件实例刚刚被创建时执行 | 1.6.3 |
attached | 无 | 在组件实例进入页面节点树时执行 | 1.6.3 |
ready | 无 | 在组件在视图层布局完成后执行 | 1.6.3 |
moved | 无 | 在组件实例被移动到节点树另一个位置时执行 | 1.6.3 |
detached | 无 | 在组件实例被从页面节点树移除时执行 | 1.6.3 |
error | Object Error | 每当组件方法抛出错误时执行 | 2.4.1 |
组件所在页面的生命周期
还有一些特殊的生命周期,它们并非与组件有很强的关联,但有时组件需要获知,以便组件内部处理。这样的生命周期称为“组件所在页面的生命周期”,在 pageLifetimes
定义段中定义。其中可用的生命周期包括:
生命周期 | 参数 | 描述 | 最低版本 |
---|---|---|---|
show | 无 | 组件所在的页面被展示时执行 | 2.2.3 |
hide | 无 | 组件所在的页面被隐藏时执行 | 2.2.3 |
resize | Object Size | 组件所在的页面尺寸变化时执行 | 2.4.0 |
routeDone | 无 | 组件所在页面路由动画完成时执行 | 2.31.2 |
注意:自定义 tabBar 的 pageLifetime 不会触发。
代码示例
Component({pageLifetimes: {show: function() {// 页面被展示},hide: function() {// 页面被隐藏},resize: function(size) {// 页面尺寸变化}}
})
插槽
什么是插槽
启用多插槽
定义多插槽
组件通信
组件间通信
组件间的基本通信方式有以下几种。
- WXML 数据绑定:用于父组件向子组件的指定属性设置数据,仅能设置 JSON 兼容数据(自基础库版本 2.0.9 开始,还可以在数据中包含函数)。具体在 组件模板和样式https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/wxml-wxss.html 章节中介绍。
- 事件:用于子组件向父组件传递数据,可以传递任意数据。
- 如果以上两种方式不足以满足需要,父组件还可以通过
this.selectComponent
方法获取子组件实例对象,这样就可以直接访问组件的任意数据和方法。
监听事件
事件系统是组件间通信的主要方式之一。自定义组件可以触发任意的事件,引用组件的页面可以监听这些事件。关于事件的基本概念和用法,参见 事件 。
监听自定义组件事件的方法与监听基础组件事件的方法完全一致:
代码示例:
<!-- 当自定义组件触发“myevent”事件时,调用“onMyEvent”方法 -->
<component-tag-name bindmyevent="onMyEvent" />
<!-- 或者可以写成 -->
<component-tag-name bind:myevent="onMyEvent" />
Page({onMyEvent: function(e){e.detail // 自定义组件触发事件时提供的detail对象}
})
触发事件
自定义组件触发事件时,需要使用 triggerEvent
方法,指定事件名、detail对象和事件选项:
代码示例:
在开发者工具中预览效果
<!-- 在自定义组件中 -->
<button bindtap="onTap">点击这个按钮将触发“myevent”事件</button>
Component({properties: {},methods: {onTap: function(){var myEventDetail = {} // detail对象,提供给事件监听函数var myEventOption = {} // 触发事件的选项this.triggerEvent('myevent', myEventDetail, myEventOption)}}
})
触发事件的选项包括:
选项名 | 类型 | 是否必填 | 默认值 | 描述 |
---|---|---|---|---|
bubbles | Boolean | 否 | false | 事件是否冒泡 |
composed | Boolean | 否 | false | 事件是否可以穿越组件边界,为false时,事件将只能在引用组件的节点树上触发,不进入其他任何组件内部 |
capturePhase | Boolean | 否 | false | 事件是否拥有捕获阶段 |
关于冒泡和捕获阶段的概念,请阅读 事件 章节中的相关说明。
代码示例:
在开发者工具中预览效果
// 页面 page.wxml
<another-component bindcustomevent="pageEventListener1"><my-component bindcustomevent="pageEventListener2"></my-component>
</another-component>
// 组件 another-component.wxml
<view bindcustomevent="anotherEventListener"><slot />
</view>
// 组件 my-component.wxml
<view bindcustomevent="myEventListener"><slot />
</view>
// 组件 my-component.js
Component({methods: {onTap: function(){this.triggerEvent('customevent', {}) // 只会触发 pageEventListener2this.triggerEvent('customevent', {}, { bubbles: true }) // 会依次触发 pageEventListener2 、 pageEventListener1this.triggerEvent('customevent', {}, { bubbles: true, composed: true }) // 会依次触发 pageEventListener2 、 anotherEventListener 、 pageEventListener1}}
})
获取组件实例
可在父组件里调用 this.selectComponent
,获取子组件的实例对象。
调用时需要传入一个匹配选择器 selector
,如:this.selectComponent(".my-component")
。
selector
详细语法可查看 selector 语法参考文档。
代码示例:
在开发者工具中预览效果
// 父组件
Page({data: {},getChildComponent: function () {const child = this.selectComponent('.my-component');console.log(child)}
})
在上例中,父组件将会获取 class
为 my-component
的子组件实例对象,即子组件的 this
。
注意 :默认情况下,小程序与插件之间、不同插件之间的组件将无法通过 selectComponent
得到组件实例(将返回 null
)。如果想让一个组件在上述条件下依然能被 selectComponent
返回,可以自定义其返回结果(见下)。
自定义的组件实例获取结果
若需要自定义 selectComponent
返回的数据,可使用内置 behavior
: wx://component-export
从基础库版本 2.2.3 开始提供支持。
使用该 behavior 时,自定义组件中的 export
定义段将用于指定组件被 selectComponent
调用时的返回值。
代码示例:
在开发者工具中预览效果
// 自定义组件 my-component 内部
Component({behaviors: ['wx://component-export'],export() {return { myField: 'myValue' }}
})
<!-- 使用自定义组件时 -->
<my-component id="the-id" />
// 父组件调用
const child = this.selectComponent('#the-id') // 等于 { myField: 'myValue' }
在上例中,父组件获取 id
为 the-id
的子组件实例的时候,得到的是对象 { myField: 'myValue' }
。
子组件的‘sync’事件
Behaviors
behaviors
是用于组件间代码共享的特性,类似于一些编程语言中的 “mixins” 或 “traits”。
每个 behavior
可以包含一组属性、数据、生命周期函数和方法。组件引用它时,它的属性、数据和方法会被合并到组件中,生命周期函数也会在对应时机被调用。 每个组件可以引用多个 behavior
,behavior
也可以引用其它 behavior
。
使用npm包
Vant组件库
Vant Weapp - 轻量、可靠的小程序 UI 组件库
使用 Vant 组件
安装完 Vant 组件库之后,可以在 app.json 的 usingComponents 节点中引入需要的组件,即可在 wxml 中 直接使用组件。
Vant Weapp 使用 CSS 变量来实现定制主题。 关于 CSS 变量的基本用法,请参考 MDN 文档: https://developer.mozilla.org/zh-CN/docs/Web/CSS/Using_CSS_custom_properties
API Promise化
默认情况下,小程序官方提供的异步 API 都是基于回调函数实现的,例如,网络请求的 API 需要按照如下的方 式调用:
缺点:容易造成回调地狱的问题,代码的可读性、维护性差!
async getInfo() {const {data: res} = await wx.p.request({method: 'GET',url: 'https://applet-base-api-t.itheima.net/get',data: {name: 'zs',age: 20}})console.log(res)},
全局数据共享
1. 安装 MobX 相关的包
在项目中运行如下的命令,安装 MobX 相关的包: 注意:MobX 相关的包安装完毕之后,记得删除 miniprogram_npm 目录后,重新构建 npm。
// 在这个 JS 文件中,专门来创建 Store 的实例对象
import { observable, action } from 'mobx-miniprogram'export const store = observable({// 数据字段numA: 1,numB: 2,activeTabBarIndex: 0,// 计算属性get sum() {return this.numA + this.numB},// actions 函数,专门来修改 store 中数据的值updateNum1: action(function (step) {this.numA += step}),updateNum2: action(function (step) {this.numB += step}),updateActiveTabBarIndex: action(function(index) {this.activeTabBarIndex = index})
})
Store中的成员绑定到页面中:
// pages/message/message.js
import { createStoreBindings } from 'mobx-miniprogram-bindings'
import { store } from '../../store/store'Page({/*** 页面的初始数据*/data: {},/*** 生命周期函数--监听页面加载*/onLoad: function (options) {this.storeBindings = createStoreBindings(this, {store,fields: ['numA', 'numB', 'sum'],actions: ['updateNum1']})},btnHandler1(e) {// console.log(e)this.updateNum1(e.target.dataset.step)},/*** 生命周期函数--监听页面初次渲染完成*/onReady: function () {},/*** 生命周期函数--监听页面显示*/onShow: function () {},/*** 生命周期函数--监听页面隐藏*/onHide: function () {},/*** 生命周期函数--监听页面卸载*/onUnload: function () {this.storeBindings.detroyStoreBindings()},/*** 页面相关事件处理函数--监听用户下拉动作*/onPullDownRefresh: function () {},/*** 页面上拉触底事件的处理函数*/onReachBottom: function () {},/*** 用户点击右上角分享*/onShareAppMessage: function () {}
})
<!--pages/message/message.wxml-->
<view>{{numA}} + {{numB}} = {{sum}}</view>
<van-button type="primary" bindtap="btnHandler1" data-step="{{1}}">numA + 1</van-button>
<van-button type="danger" bindtap="btnHandler1" data-step="{{-1}}">numA - 1</van-button><view>~~~~~~</view><my-numbers></my-numbers>
Store中的成员绑定到组件中:
// components/numbers/numbers.js
import { storeBindingsBehavior } from 'mobx-miniprogram-bindings'
import { store } from '../../store/store'Component({behaviors: [storeBindingsBehavior],storeBindings: {// 数据源store,fields: {numA: 'numA',numB: 'numB',sum: 'sum'},actions: {updateNum2: 'updateNum2'}},/*** 组件的属性列表*/properties: {},/*** 组件的初始数据*/data: {},/*** 组件的方法列表*/methods: {btnHandler2(e) {this.updateNum2(e.target.dataset.step)}}
})
在组件中使用Store中的成员
<!--components/numbers/numbers.wxml-->
<view>{{numA}} + {{numB}} = {{sum}}</view>
<van-button type="primary" bindtap="btnHandler2" data-step="{{1}}">numB + 1</van-button>
<van-button type="danger" bindtap="btnHandler2" data-step="{{-1}}">numB - 1</van-button>
分包
什么是分包
分包指的是把一个完整的小程序项目,按照需求划分为不同的子包,在构建时打包成不同的分包,用户在使用 时按需进行加载
分包的好处
对小程序进行分包的好处主要有以下两点:
⚫ 可以优化小程序首次启动的下载时间
⚫ 在多团队共同开发时可以更好的解耦协
分包预下载指的是:在进入小程序的某个页面时,由框架自动预下载可能需要的分包,从而提升进入后续分包 页面时的启动速度
"preloadRule": {"pages/contact/contact": {"packages": ["p1"],"network": "wifi" //指定网络(all是所有网路模式)}}