全局数据共享
1. 全局数据共享介绍
全局数据共享即状态管理
,是为了解决组件之间数据共享的问题,将数据统一存到Store
仓库里,各组件都能直接访问仓库内的数据,避免了各组件间频繁的数据传递等问题。
类似的有Vue
中的Vuex
,Redux
,Mobx
等。
不使用Store
:
使用Store
:
2. 小程序中的全局数据共享方案
在小程序中,可使用mobx-miniprogram
配合mobx-miniprogram-bindings
实现全局数据共享。
mobx-miniprogram
:用来创建Store
实例对象mobx-miniprogram-bindings
:用来把Store
中的共享数据或方法,绑定到组件或页面中使用
3. 安装Mobx相关的包
npm install --save mobx-miniprogram mobx-miniprogram-bindings
注意:安装完成后记得重新构建npm
4. 创建Mobx中Store实例
项目根目录下创建store文件夹用于存放Mobx相关的JS文件
创建store.js用来创建store实例
store.js:
//在这个JS文件里,专门来创建Store的实例对象
import { action, observable } from 'mobx-miniprogram'
export const store = observable({
//数据字段
numA: 1,
numB: 2,
//计算属性:当numA或numB变化时,自动更新sum的值
get sum() {
return this.numA + this.numB
},
// actions 方法,用来修改store中的数据
updateNum1: action(function (step) {
this.numA += step
}),
updateNum2: action(function (step) {
this.numB += step
})
})
注意:
- 计算属性的值是==只读==的,不能也不需要对其进行手动修改
- ==直接修改store里的数据可能会带来危险==,所以一般在actions方法里修改store里的数据
5. 页面中使用Store成员
5.1 在页面的JS中写入以下代码:
// 页面的.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']
})
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
this.storeBindings.destroyStoreBindings()
},
})
代码分析:
- 引入
mobx
的createStoreBindings
方法和我们创建的store
实例:
import { createStoreBindings } from "mobx-miniprogram-bindings";
import { store } from "../../store/store";
createStoreBindings
方法可以将Store
中的数据或方法绑定到我们的页面中
- 在页面加载时,绑定
Store
:
onLoad: function (options) {
this.storeBindings = createStoreBindings(this,{
store,
fields:['numA','numB','sum'],
actions:['updateNum1']
})
},
createStoreBindings
方法接收两个参数,一个是this
代表当前页面的实例,第二参数是配置对象,包含三个属性:
store
代表数据源fields
代表我们需要将哪些字段绑定到我们的页面中actions
代表我们需要将哪些方法绑定到我们的页面中
createStoreBindings
的调用有一个返回值,我们将这个返回值挂载到了当前页面上作为一个自定义属性storeBindings
而存在,这样我们就可以在页面卸载时利用storeBindings
来清理挂载的Store实例
- 在页面卸载时接触绑定的
Store
:
onUnload: function () {
this.storeBindings.destroyStoreBindings()
},
调用destroyStoreBindings
方法即可进行清理Store
5.2 在页面上使用Store
数据
页面的.wxm
结构:
<view>
{{numA}} +{{numB}} = {{sum}}
<button type="primary" bindtap="btn1" data-step="{{1}}">numA+1</button>
<button type="primary" bindtap="btn1" data-step="{{-1}}">numA-1</button>
</view>
在页面的JS中添加按钮tap事件的处理函数:
btn1(e){
this.updateNum1(e.target.dataset.step)
}
6. 组件中使用Store成员
6.1 在组件的JS中写入以下代码:
// components/numbers/numbers.js
import {storeBindingsBehavior} from "mobx-miniprogram-bindings"
import {store} from '../../store/store'
Component({
//通过storeBindingsBehavior来实现自动绑定
behaviors:[storeBindingsBehavior],
storeBindings:{
//指定要绑定的Store
store,
fields:{
// 绑定字段的第1种方式
numA:()=>store.numA,
// 绑定字段的第2种方式
numB:(store)=>store.numB,
// 绑定字段的第3种方式
sum:'sum'
},
actions:{
updateNum2:'updateNum2'
}
},
/**
* 组件的属性列表
*/
properties: {
},
/**
* 组件的初始数据
*/
data: {
},
/**
* 组件的方法列表
*/
methods: {
}
})
6.2 在组件上使用Store
数据
组件的.wxm
结构:
{{numA}}+{{numB}}={{sum}}
<button type="primary" bindtap="Cbtn1" data-step="{{1}}">CnumA+1</button>
<button type="primary" bindtap="Cbtn1" data-step="{{-1}}">CnumA-1</button>
在组件JS中的methods
方法列表中加入添加按钮tap事件的处理函数:
Cbtn1(e){
this.updateNum2(e.target.dataset.step)
},
分包
1. 基础概念
- 什么是分包?
分包指的是把一个完整的小程序项目,按照需求划分为不同的之包,在构建时打包成不同的分包,用户在使用时按需进行加载。
分包的好处?
-
- 可以优化小程序首次启动的下载时间
- 在多团队共同开发时可以更好的解耦协作
- 分包前项目的构成
分包前,小程序项目中所有的页面和资源都被打包到了一起,导致整个项目体积过大,影响小程序首次启动的下载时间。
- 分包后项目的构成
分包后,小程序项目由1个主包+多个分包组成:
- 主包:一般只包含项目的启动页面或TabBar页面、以及所有分包都需要用到的一些公共资源
- 分包:只包含和当前页面有关的页面和私有资源
分包的加载规则
-
在小程序启动时,默认会下载主包并启动主包内页面
-
- tabBar页面需要放到主包中
当用户进入分包内某个页面时,客户端会把对应的分包下载下来,下载完成后再进行展示
- 非tabBar页面可以按照功能的不同, 划分为不同的分包之后,进行按需下载
- 分包的体积限制
目前,小程序分包的大小有以下两个限制:
- 整个小程序所有分包大小不超过==16M==(主包+所有分包)
- 单个分包/主包大小不能超过==2M==
2. 使用分包
配置方法
app.json中添加以下分包的配置,保存后会自动生成相应的文件:
//app.json
"subpackages": [
{
"root":"pkgA",
"pages": [
"pages/cat/cat",
"pages/dog/dog"
]
},
{
"root":"pkgB",
"pages": [
"pages/apple/apple"
]
}
],
- 查看分包的体积大小
打包原则
- 小程序会按
subpackages
的配置进行分包,subpackages
之外的目录将被打包到主包中 主包也可以有自己的
pages
(即最外层的pages
字段)"pages":[ "pages/home/home", "pages/message/message", "pages/contact/contact" ],
tabBar
页面必须在主包内
如上代码即是
tabBar
页面的配置,配置到了主包的pages
里- 分包之间不能互相嵌套
- 小程序会按
引用原则
- 主包 无法引用分包内的私有资源
- 分包之间不能相互引用私有资源
- 分包可以引用主包内的公共资源
## 3. 独立分包
- 什么是独立分包
独立分包本质上也是分包,只不过它比较特殊,可以独立于主包和其它分包而单独运行。
- 独立分包和普通分包的区别
最主要的区别:是否依赖于主包才能运行
* 普通分包必须依赖于主包才能运行
>必须先进入主包才能跳到普通分包
* 独立分包可以在不下载主包的情况下,独立运行
- 独立分包的应用场景
开发者可以按需,将某些具有一定功能独立性的页面配置到独立分包中,原因如下:
* 当小程序从普通的分包页面启动时,需要首先下载主包
* 而独立分包不依赖主包即可运行,可以很大程度上提升分包页面的启动速度
>注意:一个小程序中可以有多个独立分包
- 独立分包的配置方法
独立分包的目录结构于普通分包一样,独立分包只需在JSON
配置中通过independent
进行声明:
//app.json
//pkgB设置为独立分包
"subpackages": [
{
"root":"pkgA",
"name": "p1",
"pages": [
"pages/cat/cat",
"pages/dog/dog"
]
},
{
"root":"pkgB",
"name": "p2",
"pages": [
"pages/apple/apple"
],
"independent": true
}
],
- 独立分包的引用原则
独立分包和普通分包以及主包之间,是相互隔绝的,不能相互引用批次的资源!例如:
* 主包无法引用独立分包内的私有资源
* 独立分包之间,不能相互引用私有资源
* 独立分包和普通分包之间,不能相互引用私有资源
* **特别注意**:独立分包中不能引用主包内的公共资源
## 4. 分包预下载
分包预下载指的是:在进入小程序的某个页面时,由框架自动预下载可能需要的分包
,从而提升进入后续分包页面时的启动速度。
配置分包的预下载
预下载分包的行为,会在进入指定的页面时触发。在app.json
中,使用preloadRule
节点定义分包的预下载规则,示例代码如下:"preloadRule": { "pages/contact/contact":{ "packages": ["p1"], "network": "all" } }, "subpackages": [ { "root":"pkgA", "name": "p1", "pages": [ "pages/cat/cat", "pages/dog/dog" ] }, { "root":"pkgB", "name": "p2", "pages": [ "pages/apple/apple" ], "independent": true } ],
上述代码配置的是打开
pages/contact/contact
页面时,在任意网络环境下都会预下载p1
分包。打开
pages/contact/contact
页面时查看调试器控制台会有正在预下载p1
和预下载成功的提示:- 分包预下载的限制
同一个分包的页面享有共同的预下载大小限额2M,例如:
案例:自定义tabBar
1.案例效果
在此案例中,用到的主要知识点如下:
- 自定义组件
- Vant组件库
- MobX数据共享
- 组件样式隔离
- 组件数据监听器
- 组件的behaviors
- Vant 样式覆盖
2. 实现步骤
- 配置信息
在app.json
文件的tabBar
中添加"custom": true
同时保留list里的配置项:
"tabBar": {
"custom": true,
"list": [{
"pagePath": "pages/home/home",
"text": "首页",
"iconPath": "/images/tabs/home.png",
"selectedIconPath": "/images/tabs/home-active.png"
},{
"pagePath": "pages/message/message",
"text": "消息",
"iconPath": "/images/tabs/message.png",
"selectedIconPath": "/images/tabs/message-active.png"
},{
"pagePath": "pages/contact/contact",
"text": "联系我们",
"iconPath": "/images/tabs/contact.png",
"selectedIconPath": "/images/tabs/contact-active.png"
}]
},
- 添加tabBar代码文件
项目根目录创建custom-tab-bar
文件夹,然后右键此文件夹新建Component
,起名为index
此时页面底部显示:
表示添加tabBar代码文件和配置成功
- 编写tabBar代码
custom-tab-bar/index.wxml
:
<!--使用vant的van-tabbar 组件-->
<van-tabbar active="{{ active }}" bind:change="onChange" active-color="#13A7A0">
<van-tabbar-item wx:for="{{list}}" wx:key="index" info="{{item.info?item.info:''}}">
<image
slot="icon"
src="{{ item.iconPath }}"
mode="aspectFit"
style="width: 25px; height: 25px;"
/>
<image
slot="icon-active"
src="{{ item.selectedIconPath }}"
mode="aspectFit"
style="width: 25px; height: 25px;"
/>
{{item.text}}
</van-tabbar-item>
</van-tabbar>
`custom-tab-bar/index.wxss`:
```css
/* 修改van-tabbar样式进行样式覆盖 */
.van-tabbar-item {
--tabbar-item-margin-bottom:0;
}
```
`custom-tab-bar/index.js`:
```javascript
// custom-tab-bar/index.js
import { storeBindingsBehavior } from "mobx-miniprogram-bindings"
import { store } from '../store/store'
Component({
//在自定义组件中使用 Vant Weapp 组件时,需开启styleIsolation: 'shared'才能进行样式覆盖
options: {
styleIsolation: 'shared'
},
//通过storeBindingsBehavior来实现自动绑定
behaviors: [storeBindingsBehavior],
storeBindings: {
//指定要绑定的Store
store,
fields: {
sum: 'sum',
active:'active'
},
actions:{
changeActive:'changeActive'
},
},
/**
* 数据监听器
*/
observers:{
"sum":function (val) {
// 赋值操作
this.setData({
'list[1].info':val
})
}
},
/**
* 组件的属性列表
*/
properties: {
},
/**
* 组件的初始数据
*/
data: {
list: [{
pagePath: "/pages/home/home",
text: "首页",
iconPath: "/images/tabs/home.png",
selectedIconPath: "/images/tabs/home-active.png"
}, {
pagePath: "/pages/message/message",
text: "消息",
// 消息数量
info: 0,
iconPath: "/images/tabs/message.png",
selectedIconPath: "/images/tabs/message-active.png"
}, {
pagePath: "/pages/contact/contact",
text: "联系我们",
iconPath: "/images/tabs/contact.png",
selectedIconPath: "/images/tabs/contact-active.png"
}]
},
/**
* 组件的方法列表
*/
methods: {
onChange(event) {
// event.detail为选中项索引
// 调用store里的修改tabBar选中项索引的函数
this.changeActive(event.detail)
// 手动实现页面跳转
wx.switchTab({
url: this.data.list[event.detail].pagePath,
})
},
}
})
```
`store/store.js`:
```javascript
//在这个JS文件里,专门来创建Store的实例对象
import { action, observable } from 'mobx-miniprogram'
export const store = observable({
//数据字段
numA: 1,
numB: 2,
// tabBar选中项索引
active: 0,
//计算属性:当numA或numB变化时,自动更新sum的值
get sum() {
return this.numA + this.numB
},
// actions 方法,用来修改store中的数据
updateNum1: action(function (step) {
this.numA += step
}),
updateNum2: action(function (step) {
this.numB += step
}),
changeActive: action(function (index) {
this.active = index
})
})
```
详细步骤,可以参考小程序官方文档:
https://developers.weixin.qq.com/miniprogram/dev/framework/ability/custom-tabbar.html