3 组件
约 2247 个字 304 行代码 预计阅读时间 11 分钟
1 自定义组件
- 组件的
.json
文件中需要声明components: true
- 组件的
.js
文件中调用Component()
函数以进行初始化 - 组件的事件处理函数需要定义到
methods
节点中(进行一个套娃)
1.1 创建组件
- 在根目录下新建
components
文件夹,用于存放所有组件 - 新建组件文件夹
test
,在该路径下右键选择 “新建 Component” - 输入组件名称,自动生成组件对应的 4 个文件
1.2 引用组件
分为“全局引用” & “局部引用”
- 全局引用的组件可以在每一个页面中使用
- 局部引用的组件仅能在当前页面中使用
1.3 组件样式
- 组件样式具有隔离性
app.wxss
中定义的全局样式对组件无效(类选择器)- id 选择器、属性选择器、标签选择器不受样式隔离影响
- 所以建议大家在引用了组件的界面中尽量使用class选择器,避免样式冲突
- 修改样式隔离选项
isolated
- 默认,内外互不干扰apply-shared
- 页面覆盖组件shared
- 互相影响,包括页面中其他设置了apply-shared / shared
的组件
1.4 数据 / 方法 / 属性
- 用于组件渲染的私有数据需要定义到组件的
data
节点中 - 组件的 事件处理函数 / 自定义方法 需要定义到
method
节点中 properties
是组件的对外属性,用于接收外界传递给组件的数据data
&properties
均为可读可写(这俩实际上指向同一块空间),都可以用setData
重新赋值
1.5 数据监听器
用于监听&响应任何 数据/属性 字段的变化,从而执行特定操作
<view>{{n1}} + {{n2}} = {{sum}}</view>
<view style="background-color: {{color}}">颜色值:{{color}}</view>
data: { n1: 0, n2: 0, sum: 0,
rgb:{ r:0, g:0, b:0},
color: '0,0,0'
},
observe: {
'key_1, key_2': funtcion(neo_val_1, neo_val_2) {
do sthing;
},
// 监听数据变化
'n1, n2': fucntion(v1, v2) {
this.setData({sum: v1 + v2})
},
// 监听属性变化
'rgb.r rgb.g rgb.b': function(v1, v2, v3) {
this.setData({ color: `${v1}, ${v2}, ${v3}`})
},
// 监听某个对象的所有属性
'rgb.**': function(obj) {
this.setData({ color: `${obj.r}, ${obj.g}, ${obj.b}`})
}
}
1.6 纯数据字段
既不用于页面渲染,又不传递给其他组件的数据
- 在
Component - options
中设置pureDataPattern: 正则表达式
,符合规则的字段将被视为“纯数据字段” - 纯数据字段可以被监听
1.7 组件的生命周期函数
函数名 | 描述 |
---|---|
created | 被创建时执行 |
attached | 实例进入页面节点树时执行 |
ready | 在渲染完成后执行 |
moved | 实例被移动到节点树另一位置时执行 |
detached | 实例从节点树中移除时执行 |
error(Obj err) | 每当抛出错误就执行 |
created
- 不能调用
setData
- 一般用于给
this
指针添加自定义属性字段
- 不能调用
attached
this.data
初始化完毕- 进行一些初始化工作(比如拉取初始数据)
detached
- 退出页面时,会触发当前页面中每一个组件的
detached
函数 - 适合做一些清理工作
- 退出页面时,会触发当前页面中每一个组件的
- 以上生命周期函数应当在
lifetimes
节点中进行声明
1.8 监听外层页面生命周期
自定义组件可以监听外界页面的三个生命周期:show / hide / resize(Obj size)
- 用于监听页面生命周期的函数应当在
pageLifetimes
节点中定义
4.2 独立分包
也是分包的一种,但是可以独立于主包/其他分包单独运行
- 一个小程序可以同时拥有多个独立分包
- 独立分包 与 普通分包&&主包 之间互相隔绝,不能相互引用资源 ⚠️ 独立分包不能使用主包中的公共资源
- 普通分包必须依赖于主包运行
- 应用场景:具有一定功能独立性的页面(不用下载主包,提升分包页面启动速度)
- 配置方法
1.9 插槽 slot
生效于 组件中 ,类似于一个 html 占位符,后续视情况由 使用者 插入具体的 wxml 内容
- 在小程序中,默认每个自定义组件中 只允许使用一个
<slot>
标签进行占位 - 启用多个插槽 需要手动在
page.js
中做如下设置- 启用多个插槽时,需要通过
name
来对不同插槽进行区分 - 在使用时,通过
slot
来指定内容插入的具体位置
- 启用多个插槽时,需要通过
1.10 父子组件通信
实现父子组件通信有以下三种方式:
-
属性绑定:只能 父 to 子,只能兼容
json
格式的数据(不能传递方法)- 子组件中的对应数据发生修改不会影响父组件中的源数据
-
事件绑定:只能 子 to 父,可以传递任意数据
- 在父组件的
js
文件中定义函数,以通过自定义事件进行数据传递 - 在父组件的
html
文件中通过自定义事件引用(1)中定义的函数 - 在子组件的
js
文件中调用this.triggerEvent('eventName', {/*参数*/})
,从而将参数发送给父组件 - 在父组件的
js
文件中调用e.detail
获取子组件传递的数据// 1 - 在父组件中定义 供子组件 调用的函数 syncCount() { do sthing; } // 3 - 子组件向父组件传参 // 假设我们在子组件的 +1按钮 上绑定了 addCount 函数 methods: { addCount() { this.setData({ count: this.properties.count + 1 }); // 同步修改 this.triggerEvent('sync', {value: this.properties.count}); } } // 4 - 在父组件中获取修改(修改 1 中的定义项得到) syncCount(e) { this.setData({ count: e.detail.value }) }
- 在父组件的
-
获取组件实例:
父组件可以通过
this.selectComponent("id / class选择器")
获取子组件实例对象,访问子组件 的所有数据和方法
1.11 behaviors - 不太用
用于实现 不同组件间 共享代码
behavior
可以包含一组 属性 / 数据 / 生命周期函数 / 方法,当被引用时,上述内容将被自动合并到引用的组件中- 一个组件可以引用多个
behavior
- 一个
behavior
可以引用其他behavior
- 一个组件可以引用多个
- 创建
behavior
- 在root/behaviors
下单独的js
文件中进行 - 导入并使用
behavior
- 同名字段的覆盖 & 组合
组件及其引用的
behavior
中可以拥有同名字段,处理规则详见官方文档
2 使用 npm 包
- 小程序中使用 npm 第三方包的限制 - 能用的不多
- 不支持依赖于
Node.js
内置库的包 - 不支持依赖于 浏览器内置对象 的包(比如
ajax
/jquery
) - 不支持依赖于 C++插件 的包
- 不支持依赖于
下面以使用 vant 组件库为例,vant 官方文档
- 可以通过在 element / :root 下定义 CSS 变量实现自定义主题样式
API Promise 化
- 默认情况下,小程序官方提供的 异步API 都是基于 回调函数 实现的(比如 request 要求的 success / fail / complete)
- API 的
Promise
化指:通过额外配置,将官方基于回调的 API 改装为基于Promise
的 API,从而提高代码的可维护性 - 小程序的 API
Promise
化主要依赖于第三方包miniprogram-api-promise
- 安装命令
npm install --save miniprogram-api-promise@1.0.4
(根目录下) - 构建 npm 包
- 删除
mini-program
文件目录 - 点击 ‘工具’ - ‘构建 npm’
- 展开
mini-program
目录,查看是否构建完成ß
- 删除
- 按需导入 npm 包
- 安装命令
3 全局共享 - MobX
用于解决组件之间 数据共享 的问题
一直报错可以使用 工具-构建npm
-
小程序中一般使用 mobx-miniprogram + mobx-miniprogram-bindings 作为解决方案:
-
mobx-miniprogram 用于创建 Store 实例对象
-
mobx-miniprogram-bindings 将 Store 中用于共享的 数据 / 方法 绑定到 组件 / 页面 中进行使用
-
-
MobX 安装
-
在项目根目录下执行如下命令
npm install --save mobx-miniprogram@4.13.2 mobx-miniprogram-bindings@1.2.1
-
构建
-
-
MobX 使用
- 创建 Store 实例 - 在根目录下创建
./store
路径,创建store.js
@store.js import {observable} from 'mobx-miniprogram'; // 类似于 java 中的一个工具类? export const store = observable({ // 数据字段 numA: 1, numB: 2, // 计算属性 - 结果依赖于数据字段 get sum() { return this.numA + this.numB }, // actions - 方法,用于修改 store 中的数据 updataNumA: action(function(step) { this.numA += step; }), updataNumB: action(function(step) { this.numB += step; }) })
- 将 Store 绑定到页面
@page.js import {createStoreBindings} from 'mobx-miniprogram-bindings' import {store} from '../../store/store' // export 的数据源对象 Page({ onLoad: function() { // 绑定 this.storeBindings = createStoreBindings(this, { store, // 数据源名称 fields: ['numA', 'numB', 'sum'], // 需要的数据字段(按需) actions: ['updateNumA'] // 需要的方法(按需) }) }, onUnLoad: function() { // 清理 this.storeBindings.destroySotreBindings(); } })
- 在页面中使用 Store 成员
- 在组件中绑定 Store 成员(使用略)
import {storeBindingBehavior} from 'mobx-miniprogram-bindings' import {store} from '../../store/store' Component({ behaviors: [storeBindingBehavior], // 通过该behavior自动绑定 storeBindings: { store, fields: { // 按需绑定数据字段,下面列出三种绑定方式 numA: () => store.numA, numB: (store) => store.numB, sum: 'sum' // 前:映射后的名字(本页中使用的名字),后:源数据名字 }, actions: { // 按需绑定方法 updateNumB: 'updateNumB' } } })
- 创建 Store 实例 - 在根目录下创建
4 分包
- 我们将完整的小程序项目,按照需求划分为不同的子包,并在构建时分别打包,便于缩短首次下载时间
- 分包前:小程序中的所有 页面 & 资源 被打包在一起,导致项目体积大,首次运行需要的下载时间长
- 分包后:1 * 主包 + n * 分包
- 主包:启动页面 & tabBar页面 + 公共资源
- 分包:仅包含与当前分包有关的页面 + 私有资源(不能被其他包访问)
- 加载规则
- 小程序启动时,默认下载主包,并启动主包内界面(包含所有 tabBar 页面)
- 用户进入分包页面时,按需下载分包冰进行展示(非 tabBar 页面可以视情况分包)
- 体积限制
- 整个程序 < 16M
- 单个包 < 2M
4.1 配置分包
- 目录结构
- 在
app.json
的subpackages
节点中声明分包结构 - 查询分包体积 “详情” - “基本信息” - “ 本地代码” - 展开详情,即可查看主包及各分包的体积
- 打包原则
- 小程序会按照
subpackages
中的配置进行分包,没有在该节点中声明的目录将被打包到主包当中 - 主包可以拥有自己的
pages
目录(即根目录下的pages
字段及路径) TabBar
页面必须位于主包内- 分包之间不能互相嵌套
- 小程序会按照
- 引用原则
- 主包无法引用分包内的私有资源
- 分包之间不能互相引用别人的私有资源
- 分包可以引用主包内的公共资源
4.3 分包预下载
在进入某个特定页面时,自动下载可能使用的分包,提升分包页面启动速度
- 预下载行为会在 进入页面 时触发,相关规则需要在
preloadRule
中进行定义 - 同一个分包(主包)中 所有页面 涉及的预下载总大小 <= 2M
5「SAMPLE」自定义 TabBar
5.1 配置自定义 TabBar
- 配置自定义 TabBar
- 添加 TabBar 代码文件,随后在下列文件中编写相应代码
随后,这些代码会被自动渲染成为 TabBar
5.2 渲染数字徽标
-
使用
vant
提供的 TabBar 组件时,只需要为vant-tabbar-item
组件添加info="n"
的属性即可- 由于只有部分 icon 需要渲染数字徽标,我们可以使用以下的按需渲染方式
-
如果需要使用 Store 中的数据进行动态绑定的话,就参见上面的配置步骤
此时需要通过数据监听器监听 Store 中的数值变化,并使其同步到
data
中
-
重置样式
有些样式可能是通过 CSS变量 实现的,此时我们可以通过在父节点重新定义变量进行覆盖
保险起见可以再加一个默认值
tag: var(--var_name, 0px);
- 需要覆盖
vant
组件样式时,需要在comp.json
中进行如下配置 - 重置
vant-tabbar
的选中文本颜色<vant-tabbar active-color="#??????">
- 需要覆盖
5.3 自定义 TabBar 页面跳转
因为 vant 的组件里不包含超链接 orz
- 每次点击都会触发
onChange
事件,我们可以拿到其中的event.detail
以得到 active 页面 - 因为是列表渲染,我们就可以通过 index 获取对应的页面路径
-
根据拿到的路径(
/
开头),我们可以调用wx.switchTab()
进行跳转其中
url: this.data.list[event.detail].path
「问题」图标高亮无法同步变化
- 将
activeTabBarIndex
属性放置到 Store 中进行存储 -
同时,提供提供 action 对其进行更新(接受 onChange 事件获取的值进行更新)
updataActiveTabBarIndex: action(function(idx) {this.activeTabBarIndex = idx;})
-
在组件中映射
activeTabBarIndex
,并使用插值语法绑定给vant-tabbar.active
onChange
事件触发时进行同步更改