快速上手微信小程序:开发进阶
1、小程序–开发进阶
1.1 自定义组件
组件的创建
- 在项目的根目录中,鼠标右键。创建components -> test文件夹
- 在新建的components -> test文件夹上,鼠标右键,点击“新建Component"
- 键入组件的名称之后回车,会自动生成组件对应的4个文件,后缀名分别为.js,.json,.wxml和.wxss
组件的引用
- 局部引用:组件只能在当前被引用的页面内使用**(在pages中配置)**
//json
{
"usingComponents": {
"my-test1":"/components/test/test"
}
}
//wxml
<my-test1></my-test1>
- 全局引用:组件可以在每个小程序页面中使用**(在app.json中配置)**
组件与页面的区别
- 组件的.json文件中需要声明"component": true属性
- 组件的.js文件中调用的是Component()函数
- 组件的事件处理函数需要定义到 methods节点中
组件样式
- 组件样式隔离:组件不会影响到小程序页面和其它组件的样式
- app.wxss的全局样式对组件无效,只有class选择器会有样式隔离效果
- 可以通过styleIsolation修改组件的样式隔离选项
//.js
options:{
styleIsolation:'isolated'
},
//或者
//.json
{
"styleIsolation":"isolated"
}
可选值 | 默认值 | 描述 |
---|---|---|
isolated | 是 | 表示启用样式隔离,在自定义组件内外,使用 class 指定的样式将不会相互影响 |
apply-shared | 否 | 表示页面 wxss 样式将影响到自定义组件,但自定义组件 wxss 中指定的样式不会影响页面 |
shared | 否 | 表示页面 wxss 样式将影响到自定义组件,自定义组件 wxss 中指定的样式也会影响页面和其他设置了 apply-shared 或 shared 的自定义组件 |
数据、方法和属性
- 在小程序组件中,用于组件模板渲染的私有数据,需要定义到data节点中
- 在小程序组件中,事件处理函数和自定义方法需要定义到methods节点中
- 在小程序组件中,properties 是组件的对外属性,用来接收外界传递到组件中的数据
- data更倾向于存储组件的私有数据
- properties更倾向于存储外界传递到组件中的数据
数据监听器
- 数据监听器用于监听和响应任何属性和数据字段的变化,从而执行特定的操作
observers:{
'n1,n2':function name(newN1,newN2) {
this.setData({
sum:newN1+newN2
})
}
}
- 数据监听器支持监听对象中单个或多个属性的变化**(‘对象.属性A’)**
- 如果某个对象中需要被监听的属性太多,可以使用通配符******来监听对象中所有属性的变化
纯数据字段
- 纯数据字段指的是那些不用于界面渲染的data字段,既不会展示在界面上。也不会传递给其他组件
- 纯数据字段有助于提升页面更新的性能
options:{
//指定纯数据字段格式
pureDataPattern:/^_/
},
data:{
a:true,//普通数据字段
_b:true//纯数据字段
}
组件的生命周期
生命周期函数 | 参数 | 描述说明 |
---|---|---|
created | 无 | 在组件实例刚刚被创建时执行 |
attached | 无 | 在组件实例进入页面节点树时执行 |
ready | 无 | 在组件在视图层布局完成后执行 |
moved | 无 | 在组件实例被移动到节点树另一个位置时执行 |
detached | 无 | 在组件实例被从页面节点树移除时执行 |
error | Object Error | 每当组件方法抛出错误时执行 |
-
组件实例刚被创建好的时候,created生命周期函数会被触发
- 此时还不能调用setData
- 通常在这个生命周期函数中,只应该用于给组件的this添加一些自定义的属性字段
-
在组件完全初始化完毕、进入页面节点树后,attached生命周期函数会被触发
- 此时, this.data 已被初始化完毕
- 这个生命周期很有用,绝大多数初始化的工作可以在这个时机进行(例如发请求获取初始数据
-
在组件离开页面节点树后, detached生命周期函数会被触发
- 退出一个页面时,会触发页面内每个自定义组件的detached生命周期函数
- 此时适合做一些清理性质的工作
-
在小程序组件中,生命周期函数可以直接定义在Component 构造器的第一级参数中,可以在lifetimes字段内进行声明**(这是推荐的方式,其优先级最高**)。
Component({
lifetimes:{ //推荐用法
attached(){ }
},
//attached(){ }, 旧式定义方式
})
组件所在页面的生命周期
- 自定义组件的行为依赖于页面状态的变化,此时就需要用到组件所在页面的生命周期。
生命周期函数 | 参数 | 描述 |
---|---|---|
show | 无 | 组件所在的页面被展示时执行 |
hide | 无 | 组件所在的页面被隐藏时执行 |
resize | Object Size | 组件所在的页面尺寸变化时执行 |
Component({
pageLifetimes:{
show:function(){ },//页面被展示
hide:function(){ },//页面被隐藏
resize:function(size){ }//页面尺寸变化
}
})
插槽
- 提供一个< slot>节点(插槽),用于承载组件使用这提供的wxml结构,默认只允许使用单个插槽
- 多个插槽,以不同的name来区分不同的插槽
//component.js
options:{
multipleSlots:true
},
//component.wxml
<view>
<slot name="before"></slot>
<view>这里是组件的内部结构</view>
<slot name="after"></slot>
</view>
//pages.wxml
<my-test>
<view slot="before">这里通过before插槽填充的内容</view>
<view slot="after">这里通过after插槽填充的内容</view>
</my-test>
父子组件之间的通信
-
属性绑定
- 用于父组件向子组件的指定属性设置数据,仅能设置JSON兼容的数据
//父组件data节点 data: { count:0 }, // 父组件wxml <my-test5 count="{{count}}"></my-test5> <view>~~~~~~~~~</view> <view> 父组件中,count值是:{{count}}</view> //子组件properties节点 properties: { count:Number }, // 子组件wxml <view>子组件中,count值是:{{count}}</view>
-
事件绑定
- 用于子组件向父组件传递数据,可以传递任意数据
//父组件定义方法 syncCount(e){ this.setData({ count:e.detail.value }) }, //父组件wxml,使用 bind:自定义事件名称 <my-test5 count="{{count}}" bind:sync="syncCount"></my-test5> //子组件wxml <view>子组件中,count值是:{{count}}</view> <button bindtap="addCount">+1</button> //子组件方法 methods: { addCount(){ this.setData({ count:this.properties.count+1 }) this.triggerEvent('sync',{value:this.properties.count}) } }
-
获取组件实例
- 父组件还可以通过this.selectComponent()获取子组件实例对象
- 这样就可以直接访问子组件的任意数据和方法
//父组件wxml结构 <my-test5 count="{{count}}" bind:sync="syncCount" class="customA"></my-test5> <view> 父组件中,count值是:{{count}}</view> <button bindtap="getChild">获取子组件的实例对象</button> //父组件js方法 id选择器或者class选择器 getChild(){ const child = this.selectComponent('.customA') child.setData({count:child.properties.count + 1}) child.addCount() },
behaviors
- 用于实现组件代码共享的特性
- 调用Behavior(Object object)方法即可创建一个共享的 behavior实例对象,供所有的组件使用
//创建文件夹,创建文件
module.exports = Behavior({
data:{username:'zs'},
properties:{},
methods:{}
})
//js文件中使用
const myBehavior = require('../../behaviors/my-behaviors')
// components/test5/test5.js
Component({
behaviors:[myBehavior],
})
可用的节点 | 类型 | 是否必填 | 描述 |
---|---|---|---|
properties | Object Map | 否 | 同组件的属性 |
data | Object | 否 | 同组件的数据 |
methods | Object | 否 | 同自定义组件的方法 |
behaviors | String Array | 否 | 引入其它的 behavior |
created | Function | 否 | 生命周期函数 |
attached | Function | 否 | 生命周期函数 |
ready | Function | 否 | 生命周期函数 |
moved | Function | 否 | 生命周期函数 |
detached | Function | 否 | 生命周期函数 |
- 覆盖和组合规则:https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/behaviors.html
1.2 使用npm包
npm包的限制
- 不支持依赖于Node.js内置库的包
- 不支持依赖于浏览器内置对象的包
- 不支持依赖于C++插件的包
Vant Weapp
- 官方文档地址:https://youzan.github.io/vant-weapp
-
安装Vant组件库(详细参考https://youzan.github.io/vant-weapp/#/quickstart#an-zhuang)
- 通过npm安装(建议指定版本为@1.3.3)
- 构建npm包
- 修改app.json
-
使用Vant组件:
//app.json
"usingComponents": {
"van-button": "@vant/weapp/button/index"
}
//pages的wxml结构
<van-button type="primary">按钮</van-button>
-
定制全局主题样式
- CSS变量的基本用法:https://developer.mozilla.org/zh-CN/docs/Web/CSS/Using_CSS_custom_properties
- 颜色变量:https://github.com/youzan/vant-weapp/blob/dev/packages/common/style/var.less
page { //定制警告按钮的背景颜色和边框颜色 --button-danger-background-color:#C00000; --button-danger-border-color:#D60000; }
API Promise化
- 默认情况下,小程序官方提供的异步API都是基于回调函数实现的,存在回调地狱,代码的可读性、维护性差
- APl Promise化,指的是通过额外的配置,将官方提供的、基于回调函数的异步API,升级改造为基于Promise的异步API,从而提高代码的可读性、维护性,避免回调地狱的问题
//装包,需重新构建
npm i --save miniprogram-api-promise@1.0.4
//app.js
import {promisifyAll} from 'miniprogram-api-promise'
const wxp = wx.p = {}
promisifyAll(wx,wxp)
1.3 全局数据共享
-
全局数据共享(又叫做:状态管理)是为了解决组件之间数据共享的问题
-
在小程序中,可使用mobx-miniprogram配合mobx-miniprogram-bindings实现全局数据共享。
- mobx-miniprogram 用来创建Store实例对象
- mobx-miniprogram-bindings用来把Store中的共享数据或方法,绑定到组件或页面中使用
//装包,重新构建
npm i --save mobx-miniprogram@4.13.2 mobx-miniprogram-bindings@1.2.1
//创建MobX的Store实例 创建store文件夹、store.js文件
import {observable,action} from 'mobx-miniprogram'
export const store = observable({
//数据字段
numA:1,
numB:2,
//计算属性
get sum(){
return this.numA + this.numB
},
//actions方法,用来修改store中的数据
updateNum1:action(function(step){
this.numA += step
}),
updateNum2:action(function(step){
this.numB += step
}),
})
//将Store中的成员绑定到页面中 页面的.js文件
import {createStoreBindings} from 'mobx-miniprogram-bindings'
import{store} from '../../store/store'
Page({
onLoad:function(){ //监听页面加载
this.storeBindings = createStoreBindings(this,{
store, //指定要绑定的Store
fields:['numA','numB','sum'],//指定要绑定的字段数据
actions:['updateNum1']//指定要绑定的方法
})
},
onUnload:function(){//监听页面卸载
this.storeBindings.destroyStoreBindings()
}
})
//页面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>
//组件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'
}
},
})
//组件wxml
<my-numbers></my-numbers>
//组件js
methods: {
btnHandler2(e){
this.updateNum2(e.target.dataset.step)
}
}
1.4 分包
概念
-
分包指的是把一个完整的小程序项目,按照需求划分为不同的子包,在构建时打包成不同的分包,用户在使用时按需进行加载
-
优点:
- 可以优化小程序首次启动的下载时间
- 在多团队共同开发时可以更好的解耦协作
-
分包项目由1个主包 + 多个分包组成
- 主包:一般只包含项目的启动页面或TabBar页面、以及所有分包都需要用到的一些公共资源 (启动是默认下载并启动)
- 分包:只包含和当前分包有关的页面和私有资源 (进入时下载)
- 总包不超过16M,单包不超过2M
使用
- 小程序会按
subpackages
的配置进行分包,subpackages之外的目录将被打包到主包中 - 主包也可以有自己的pages(即最外层的 pages字段)
- tabBar页面必须在主包内
- 分包之间不能互相嵌套
- 主包无法引用分包内的私有资源
- 分包之间不能相互引用私有资源
- 分包可以引用主包内的公共资源
独立分包
-
独立分包本质也是分包,可以独立于主包和其他分包而单独运行
"independent": true
-
开发者可以按需,将某些具有一定功能独立性的页面配置到独立分包中
- 小程序从普通分包页面启动时,首先需要下载主包
- 独立分包不依赖主包即可运行,提升分包页面的启动速度
-
独立分包和普通分包以及主包之间,是相互隔绝的,不能相互引用彼此的资源!!
分包预下载
- 在进入小程序的某个页面时,由框架自动预下载可能需要的分包,从而提升进入后续分包页面时的启动速度
- 同一个分包中的页面享有共同的预下裁大小限额2M
//app.json
"preloadRule": {
"pages/contact/contact":{
//指定的网络模式下进行预下载
"network": "all",
//进入页面后预下载哪些分包
"packages":["pkgA"]
}
},