API Promise化,指的是通过额外的配置,将官方提供的、基于回调函数的异步 API,
升级改造为基于 Promise 的异步 API,从而提高代码的可读性、维护性,避免回调地狱的问题
默认情况下,小程序官方提供的异步API都是基于回调函数实现的,例如:网络请求的 API 需要按照如下的方式调用:
wx.request({
url: '',
method: '',
data: {},
success: () => {}, // 请求成功的回调函数
fail: () => {}, // 请求失败的回调函数
complete: () => {} // 请求完成的回调函数
})
缺点:容易造成回调地狱的问题,代码的可读性、维护性差
安装
在小程序中,实现 API Promise化 主要依赖于 miniprogram-api-promise 这个第三方的 npm包。安装步骤如下:
npm install --save miniprogram-api-promise
构建
默认情况下,安装完 npm包 后默认放置的是 node_modules 中,
但是小程序无法去读取 node_modules 的内容。此时需要进行构建的方式去将 node_modules
中对应的包迁移到 miniprogram_npm 目录下,就可使用 npm 下载的 npm包
修改 project.config.json 对应配置
{
// ...
"setting": {
// ...
"packNpmManually": true,
"packNpmRelationList": [
{
"packageJsonPath": "./package.json",
"miniprogramNpmDistDir": "./"
}
]
}
在小程序项目中进行 npm 包的构建
在 miniprogram_npm 目录下就有了 miniprogram-api-proise 包
使用
在 app.js 中去全局导入 miniprogram-api-proise 的内容,并将 Promise化的 api 挂载到 wx 顶级对象下的 p 对象
/*
在小程序入口文件中,只需要调用一次 promisifyAll() 方法,
即可实现异步 API 的 Promise 化
*/
import {
promisifyAll
} from 'miniprogram-api-promise'
// (wx 是小程序的顶级对象) 通过给 wx 挂载一个 p 的空对象,并将下标同样指向给定义的 wxp
// 因此 通过 wxp 的方式调用的 API,等同于调用 wx 中 p 对象的方法
const wxp = wx.p = {};
// 将 Promise化的 API 挂载到对应对象中
/*
promisifyAll() 会将参数1 中 wx 对象的所有 API 进行 Promise化
并最后挂载到 参数2 下 用户创建的对象上
*/
promisifyAll(wx, wxp);
通过 app.json 进行全局导入 Promise 化的 API,将该对象放置在了 wx 顶级对象的 p 对象中。
所有页面都可直接通过 wx.p 使用 Promise 化的 API
若使用时提示报错,需要在 本地设置 中启用 “将 JS 编译成 ES5”
案例演示
使用 Promise化的 API 发起一次网络请求,并将返回的结果赋值在页面中
<view class="container">
<view>
<image src="{{img}}" mode=""/>
</view>
<button bind:tap="getImg">发起图片申请</button>
</view>
Page({
data: {
img:''
},
async getImg() {
const {
data: res
} = await wx.p.request({
url: 'https://image.anosu.top/pixiv/json',
data: {},
});
this.setData({
img:res[0].url
})
}
})
import {
promisifyAll
} from 'miniprogram-api-promise'
const wxp = wx.p = {};
promisifyAll(wx, wxp);
App({})
效果展示
全局共享
全局数据共享 (又叫:状态管理) 是为了解决组件之间数据共享的问题。开发中常用的全局数据共享方案有:Vuex、Redux、Mobx 等
如若没有全局共享的数据,组件之间的传递会变得臃肿和麻烦。需要不断通过相邻的节点传递到最终目标
小程序的全局共享
在小程序中,可使用 mobx-miniprogram 配合 mobx-miniprogram-bindings 实现全局数据共享,其中:
- mobx-miniprogram 用来创建 Store 实例对象
- mobx-miniprogram-bindings 用来把 Store 中的共享数据或方法,绑定到组件或页面中使用
下载包
MobX 相关的包安装完毕后,需要删除原来的 miniprogram_npm 目录后,重新构建 npm
npm install --save mobx-miniprogram@4.13.2 mobx-miniprogram-bindings@1.2.1
构建包
需要留意 project.config.json 文件需要进行构建前的必要改动。参考之前步骤
创建目录结构
在小程序根目录中,可以创建一个 Store 目录,用来放置 Mobx实例
引入 Mobx实例对象
// 创建 Store 实例对象
import { observable } from 'mobx-miniprogram';
// 导出 MobX 的 Store 实例
export const store = observable({})
写入共享数据
通过用 get 的修饰符的函数调用时无需加括号,以变量方式调用会返回结果,实现计算属性的效果。该值是只读的
// 创建 Store 实例对象
import {
observable
} from 'mobx-miniprogram';
// 导出 MobX 的 Store 实例
export const store = observable({
numA: 1,
numB: 2,
// 计算属性
get sum() {
return this.numA + this.numB;
}
});
修改共享数据
一般外界不允许直接去修改 store 中的数据,可使用内置 action(fn) 函数去修改 MobX实例 中存放的数据字段的值
- observable({}) 用来创建 MobX 实例对象,action(fn) 方法用来修改创建的数据字段
// 创建 Store 实例对象
import {
action,
observable
} from 'mobx-miniprogram';
// 导出 MobX 的 Store 实例
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
}),
});
MobX 共享数据导入到页面
通过导入使用 mobx 创建的 store 对象,和 mobx-miniprogram-bindings 的 createStoreBindings 方法,实现绑定页面操作
该方法相当于直接将 store 中存放的字段和方法挂载在 页面的对应位置 (例如:this.data 对应 fields 中的字段)
import { createStoreBindings } from 'mobx-miniprogram-bindings';
import { store } from '../../store/store';
Page({
// 生命周期 - 页面加载
onLoad: function (options) {
// 将 mobX 数据绑定到页面上
this.storeBindings = createStoreBindings(this, {
// 数据源
store,
// 需要绑定的字段
fields: ['numA', 'numB', 'sum'],
// 需要绑定的方法
actions: ['updateNum1']
})
},
// 生命周期 - 页面卸载
onUnload: function () {
// 清理 MobX绑定到页面的数据
this.storeBindings.destroyStoreBindings();
},
})
在页面上使用 MobX 数据
通过 mobx-miniprogram-bindings 的 createStoreBindings 方法导入的 MobX 共享数据,直接可以通过调用常规数据来调用
- createStoreBindings 负责将 MobX 创建的 store 数据导入到 wx 页面实例中,它传入两个参数,
一个是挂载点 this;一个是对象,对象里面需要填入 数据源 和 字段(fields)、方法(actions) - 使用 store 中的成员,如果是 字段,直接使用 Mustache语法 即可,
如果是 方法,可以为某些元素绑定事件,调用映射过来的方法即可
<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>
import {
createStoreBindings
} from 'mobx-miniprogram-bindings';
import {
store
} from '../../store/store';
Page({
onLoad: function (options) {
// 将 mobX 数据绑定到页面上
this.storeBindings = createStoreBindings(this, {
// 数据源
store,
// 需要绑定的字段
fields: ['numA', 'numB', 'sum'],
// 需要绑定的方法
actions: ['updateNum1']
})
},
btnHandler1(e){
// 调用 MobX 传入的方法
this.updateNum1(e.target.dataset.step)
}
})
效果展示
MobX 共享数据导入到组件
通过导入使用 mobx 创建的 store 对象,和 mobx-miniprogram-bindings 的 storeBindingsBehavior 方法,实现绑定到组件操作
- 将 storeBindingsBehavior 对象导入到组件实例的 behaviors 数组中;
- 为 storeBindings 传入对应的 数据源、fields 字段,actions 方法
import {storeBindingsBehavior} from 'mobx-miniprogram-bindings';
import {store} from '../../store/store';
Component({
// 通过 storeBindingsBehavior 来实现自动绑定
behaviors:[storeBindingsBehavior],
storeBindings:{
// 数据源
store,
// 指定要绑定的字段数据
fields:{
// 三种写法
numA:()=>store.numA,
numB:(store)=>store.numB,
sum:'sum'
},
// 指定要绑定的方法
actions:{
// 可自定义指向 store 的方法
updateNum2:'updateNum2'
}
}
})
在组件上使用 MobX 数据
- 创建组件,并在 app.json 文件的 usingComponents 下注册并命名该组件。在组件中引入 store 数据。
- 通过 mobx-miniprogram-bindings 提供的 storeBindingsBehavior 导入到 组件实例的 behaviors 数组中。
- 通过 storeBindings 方法导入 MobX 创建的 store 中需要的数据。可按需要填写 数据源、字段、方法的参数
{
// ...
"usingComponents": {
"test":"/Components/test/test"
}
}
import {storeBindingsBehavior} from 'mobx-miniprogram-bindings';
import {store} from '../../store/store';
Component({
// 通过 storeBindingsBehavior 来实现自动绑定
behaviors:[storeBindingsBehavior],
storeBindings:{
// 数据源
store,
// 指定要绑定的字段数据
fields:{
// 三种写法 左边的变量可随意命名
num_A:()=>store.numA,
numB:(store)=>store.numB,
sum:'sum'
},
// 指定要绑定的方法 左边的变量可随意命名
actions:{
updateNum2:'updateNum2'
}
},
methods:{
// 组件中使用 MobX 传入的方法
btnHandler2(e){
this.updateNum2(e.target.dataset.step);
}
}
})
<view class="myComponents">
<view>
{{num_A}} + {{numB}} = {{sum}}
</view>
<van-button bindtap="btnHandler2" data-step="{{1}}">numB加1</van-button>
<van-button bindtap="btnHandler2" data-step="{{-1}}">numB减1</van-button>
</view>
效果展示
由于是共享数据,值会同步更新
蓝色区域为组件区域
不要使用 SetData 修改 MobX 字段
要更新 MobX 创建的 store 的字段数据,不应该使用 this.setData(),它不会改变 store 存储的对应值。
正确做法是 页面或组件 直接调用 Mobx 中自带的 actions 方法去修改对应的 字段数据;
MobX 会自行检查自己的 字段是否发生变化,如果变化会调用 setData 渲染界面
从页面或组件的 .js 中使用 setData 修改值,只是修改了页面的 data 数据。并没有修改 MobX 中数据
import {storeBindingsBehavior} from 'mobx-miniprogram-bindings';
import {store} from '../../store/store';
Component({
behaviors:[storeBindingsBehavior],
storeBindings:{
store,
fields:{
numB:'numB',
},
actions:{
updata:'updata'
}
},
methods:{
updataMobXdata(){
// 不能直接修改 MobX 传入的值
this.setData({
numB: this.data.numB + 1
})
}
})
MobX 会检查字段的值是发生的变化,会自行调用微信小程序的 this.setData() 把更新后的值渲染到页面
import {storeBindingsBehavior} from 'mobx-miniprogram-bindings';
import {store} from '../../store/store';
Component({
behaviors:[storeBindingsBehavior],
storeBindings:{
store,
fields:{
numB:'numB'
},
actions:{
updata:'updata'
}
},
methods:{
updataMobXdata(){
this.updata({
numB: this.data.numB + 1
})
}
}
})
import {
observable,
action
} from 'mobx-miniprogram';
export const store = observable({
numA: 1,
numB: 2,
get sum() {
return this.numA + this.numB;
},
// actions 方法,用来修改 store 中的数据
updata: action(function (fn) {
this.numB = fn.numB ?? this.numB;
this.numA = fn.numA ?? this.numA;
}),
})
错误示范
使用 setData 并没有全局同步更新
正确示范
使用 MobX 提供的 actions 方法实现同步更新
分包介绍
分包指的是把一个完整的小项目程序,按照需求划分为不同的子包,在构建时打包成不同的分包,用户在使用时按需进行加载。
分包的优势
对小程序进行分包的好处主要有以下两点:
- 可以优化小程序首次启动的下载时间
- 在多团队共同开发时可以更好的解耦操作
分包前项目的构成
分包前,小程序项目中所有的页面和资源都被打包到了一起,导致整个项目体积过大,影响小程序首次启动的下载时间
分包后的项目构成
分包后,小程序项目由一个主包 + 多个分包组成:
- 主包:一般只包含项目的启动页面或者 TabBar页面,以及所有分包都需要用到的一些公共资源
- 分包:只包含和当前分包有关的页面和私有资源
分包的加载规则
在小程序启动时,默认会下载主包并启动主包内页面
- tabBar 页面需要放在主包中
当用户进入分包内某个页面时,客户端会把对应分包下载下来,下载完成后再进行展示
- 非 tabBar 页面可以按照功能的不同,划分为不同的分包之后,进行按需下载
分包的体积限制
目前小程序分包的大小有以下两个限制:
- 整个小程序所有的分包大小不超过 16M (主包 + 分包)
- 单个分包 / 主包 大小不能超过 2M
分析结构
根据小程序项目中文件夹来划分主包和分包
修改配置文件
在 app.json 的 subpackages 节点中声明分包的结构,root 为分包的存放目录,page 为页面,name 为别名
{
// 主包的所有资源
"pages": [
"pages/index/index"
],
// 通过 subpackage 节点 声明分包的结构
"subPackages": [
{
// 第一个分包的根目录
"root": "packageA",
// 当前分包下 所有页面的相对存放路径
"pages": [
"pages/cat",
"pages/dog"
]
},
{
// 第二个分包的根目录
"root": "packageB",
// 分包的别名
"name": "pack2",
// 当前分包下 所有页面的相对存放路径
"pages": [
"pages/apple",
"pages/banana"
]
}
]
}
生成分包
在 app.json 的 subpackages 中创建分包对象后,开发者工具会自动创建对应的 文件目录。可以创建多个分包
创建别名
在每一个分包对象中,使用 name 设置别名,设置别名是为了方便后续的管理操作中查看对应包的状态
{
"pages": [
"pages/index/index"
],
"subPackages": [
{
"root":"pkgA",
"name":"pk1",
"pages":[
"pages/cat/cat",
"pages/dog/dog"
]
},
{
"root":"pkgB",
"name":"pk2",
"pages":[
"pages/apple/apple",
"pages/banana/banana"
]
}
]
}
查看包体积
小程序允许包的体积限制在 16M,每个分包限制在 2M,通过小程序的 详情 → 本地代码 中可以查看当前体积
打包原则
- 小程序会按 subpackages 的配置进行分包,subpackages 之外的目录被打包到主包中
- 主包也可以有自己的 pages (即最外层的 pages 字段)
- tabBar 页面必须在主包内
- 分包之间不能互相嵌套
引用原则
- 主包无法引用分包内的私有资源
- 分包之间不能相互引用私有资源
- 分包可以引用主包内的公共资源
介绍
独立本质上分包也是分包,只不过它比较特殊,它可以独立于主包和其他分包而单独运行
独立分包不用依赖主包,也可以独立执行,适用于登录页面或广告页面
独立分包和普通分包的区别
- 普通分包必须依赖于主包才能运行
- 独立分包可以在不下载主包的情况下独立运行
独立分包的应用场景
开发者可以按需,将某些具有一定功能独立性的页面配置到独立分包中,原因如下:
- 当小程序从普通分包页面启动时,需要首先下载主包
- 而独立分包不依赖主包即可运行,可以很大程度上提升分包页面的启动速度
当只需要执行分包的独立性业务,而不需要运行主包。即可设置该分包为独立分包
* 一个小程序可以设置多个独立分包 *
配置独立分包
为普通分包的对象属性设置 independent : true 即可为该分包声明为独立分包
{
"pages": [
"pages/index/index"
],
"subPackages": [
// ...
{
"root":"pkgB",
"name":"pk2",
"pages":[
"pages/apple/apple",
"pages/banana/banana"
],
// 通过此节点 声明当前 pkgB 分包为独立分包
"independent": true
}
]
}
打包原则
引用原则
独立分包和普通分包以及主包之间,是相互隔绝的,不能相互引用彼此的资源。例如:
- 主包无法引用独立分包内的私有资源
- 独立分包之间,不能相互引用私有资源
- 独立分包和普通分包之间,不能相互引用私有资源
- 注意:独立分包中不能引用主包内的公共资源
介绍
分包预下载指的是在小程序的某个页面时,由框架自动预下载可能需要的分包,从而提升进入后续分包页面时的启动速度。
在用户可能会访问对应分包的页面上,由框架自动预先下载需要的分包。
如果用户真的使用了该分包,则省去了等待下载时间,从而提升进入后续分包页面时的启动速度。
配置分包预下载
预下载分包的行为,会在进入指定的页面时触发。在 app.json 中,使用 preloadRule 节点定义分包的预下载规则
- network 设置指定网络模式下进行预下载
- packages 设置需要预下载的分包,可以用 root 路径 或者 name 别名
{
"pages": [
"pages/index/index"
],
// 分包的预下载规则
"preloadRule": {
// 触发分包预下载的页面路径
"pages/index/index":{
// network 表示在指定的网络下进行预下载
// 默认值为 wifi 可选值 all (不限制网络) wifi (仅 wifi 下载)
"network": "all",
// packages 表示进入页面后预先下载的哪些分包 可以为包的 root 或者 name
"packages": ["pkgA"]
}
},
"subPackages": [
{
"root":"pkgA",
"name":"pk1",
"pages":[
"pages/cat/cat",
"pages/dog/dog"
]
}
]
}
效果展示
设置分包预下载的页面当进入时,
会执行预下载分包操作
分包预下载的限制
同一个分包中的页面享有共同预下载大小限额 2M,例如:
为自己的 tabBar 栏目添加额外的效果,例如动态显示消息气泡的数值
介绍
自定义 tabBar 分为 3 大步骤,分别是:
- 配置信息
- 添加 tabBar 代码文件
- 编写 tabBar 代码
详细步骤,可以参考小程序官方给出的文档:自定义tabBar
声明自定义 tabBar
微信开发者工具中若想创建自定义 tabBar,需要在 app.json 中的 tabBar 项指定 custom 字段为 true,
同时其余 tabBar 相关配置也补充完整
所有 tab 页的 json 里需声明 usingComponents 项,也可以在 app.json 全局开启
注意:为了保证低版本兼容以及区分哪些页面是 tab 页,tabBar 的相关配置项需完整声明,
但这些字段不会作用于自定义 tabBar 的渲染
{
"pages": [
"pages/index/index",
"pages/message/message",
"pages/call/call"
],
"tabBar": {
"custom": true,
"list": [{
"pagePath": "pages/index/index",
"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/call/call",
"text": "联系我们",
"iconPath": "images/tabs/contact.png",
"selectedIconPath": "images/tabs/contact-active.png"
}
]
}
}
创建自定义 tabBar 代码目录
在代码根目录中添加入口文件(必须命名为下方文件名):
custom-tab-bar/index.js
custom-tab-bar/index.json
custom-tab-bar/index.wxml
custom-tab-bar/index.wxss
右键新建 Component 组件,并命名为 index,会自动生成对应项目依赖文件
设置完成后,会自动将该组件渲染到页面的底部 tabBar 区域展示
使用 vant 提供的 Tabbar 标签样式:官方 tabbar标签样式文档、安装 vant组件库
引入
在 app.json 或 index.json 中引入组件
"usingComponents": {
"van-tabbar": "@vant/weapp/tabbar/index",
"van-tabbar-item": "@vant/weapp/tabbar-item/index"
}
配置
导入 vant组件库 提供的演示模板,并关联 active 和 组件的方法到 js 文件,实现基本交互
<van-tabbar active="{{ active }}" bind:change="onChange">
<van-tabbar-item icon="home-o">标签</van-tabbar-item>
<van-tabbar-item icon="search">标签</van-tabbar-item>
<van-tabbar-item icon="friends-o">标签</van-tabbar-item>
<van-tabbar-item icon="setting-o">标签</van-tabbar-item>
</van-tabbar>
Component({
data: {
active: 0
},
methods: {
onChange(e) {
this.setData({
active: e.detail
});
}
}
})
效果展示
自定义图标
可以通过 slot 自定义图标,其中 icon slot 代表未选中状态下的图标,icon-active slot 代表选中状态下的图标 相关文档
<!--custom-tab-bar/index.wxml-->
<van-tabbar active="{{ active }}" bind:change="onChange">
<!-- info 是悬浮在右上角的气泡消息样式 -->
<van-tabbar-item info="3">
<image
slot="icon"
src="/images/tabs/home.png"
mode="aspectFit"
style="width: 30px; height: 18px;"
/>
<image
slot="icon-active"
src="/images/tabs/home-active.png"
mode="aspectFit"
style="width: 30px; height: 18px;"
/>
首页
</van-tabbar-item>
<van-tabbar-item icon="search">标签</van-tabbar-item>
<van-tabbar-item icon="friends-o">标签</van-tabbar-item>
<van-tabbar-item icon="setting-o">标签</van-tabbar-item>
</van-tabbar>
效果展示
遍历渲染 TabBar
按照 app.json 中定义的 list 项要求,以 wx:for 方式遍历的方式去让 vant组件库 铺设 自定义tabBar标签栏
- wx:for 遍历 list 对象进行铺设,并使用 style 属性修改 图标大小、字体大小 (注意组件样式隔离)
- 在 wxss 中使用审查元素查看 vant组件库 中查找对应的 CSS变量 去覆盖原参数,实现去除下边距
- 在 js 中为 message 对象里添加 info 属性,方便 wx:for 遍历wxml 时做 渲染判断
<van-tabbar active="{{ active }}" bind:change="onChange">
<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>
Component({
// 需要关闭组件隔离
options: {
styleIsolation: 'shared'
},
data: {
active: 0,
// 从 app.json 中的 tabBar 项目的 list 粘贴过来的
/*
app.json 中的 list 的路径不能直接给 当前 编程式导航使用
需要给前面加 /
*/
"list": [{
"pagePath": "/pages/index/index",
"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",
info: 2
},
{
"pagePath": "/pages/call/call",
"text": "联系我们",
"iconPath": "/images/tabs/contact.png",
"selectedIconPath": "/images/tabs/contact-active.png"
}
]
},
methods: {
onChange(e) {
this.setData({
active: e.detail
});
}
}
})
/* 覆盖 vant 组件 CSS变量 样式的值 去掉下边距 */
.van-tabbar-item {
--tabbar-item-margin-bottom: 0;
}
效果展示
实现气泡提示同步 sum值
通过 MobX 中的全局共享数据存储 数值,并使用监听器去动态监听其变化来执行 tabBar 重新渲染的操作
import {
storeBindingsBehavior
} from 'mobx-miniprogram-bindings';
import {
store
} from '../store/store'
Component({
options: {
styleIsolation: 'shared'
},
behaviors: [storeBindingsBehavior],
storeBindings: {
store,
fields: {
// 从全局 MobX 数据中获取 sum 值
sum: 'sum'
}
},
// 监听 sum 值的变化
observers: {
// 当 sum 值发生变化时 执行回调函数
"sum": function (val) {
this.setData({
// 将新值 赋值到 list[1].info 成员中
'list[1].info': val
})
}
},
data: {
active: 0,
"list": [{
"pagePath": "/pages/index/index",
"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",
info: 0
},
{
"pagePath": "/pages/call/call",
"text": "联系我们",
"iconPath": "/images/tabs/contact.png",
"selectedIconPath": "/images/tabs/contact-active.png"
}
]
},
/**
* 组件的方法列表
*/
methods: {
onChange(e) {
this.setData({
active: e.detail
});
}
}
})
效果展示
实现 TabBar 的页面切换
通过 tabBar标签栏 提供的 onChange 事件;当触发该事件时,使用 wx.switchTab() 进行对应路径跳转
由于存在页面渲染不同步的问题,应该将 active 属性设置为 MobX 共享数据
通过 MobX 全局管理并负责 vant组件库设置的选中和切换的 active 属性,可以解决这个问题
左侧为BUG展示:使用 setDate() 方法去改变 active,并用 wx.switchTab() 执行页面切换后,下方 tabBar 按钮的选中不同步
将 vant组件库的 tabBar标签栏 监听的 active 变量放置在 MobX 数据的 字段中
import {
observable,
action
} from 'mobx-miniprogram';
export const store = observable({
// 作为 vant组件中 active 属性的存值
activeTabBarIndex: 0,
// 改变 active 的方法
updateActiveTabBarIndex: action(function (index) {
this.activeTabBarIndex = index;
})
})
import {
storeBindingsBehavior
} from 'mobx-miniprogram-bindings';
import {
store
} from '../store/store'
Component({
behaviors: [storeBindingsBehavior],
storeBindings: {
store,
fields: {
sum: 'sum',
// 映射 MobX 到 this.data 的字段为 active
active: 'activeTabBarIndex'
},
actions: {
// 映射 MobX 到 this.methods 的字段为 updateActive
updateActive: 'updateActiveTabBarIndex'
}
},
observers: {
"sum": function (val) {
this.setData({
'list[1].info': val
});
}
},
// ...
methods: {
onChange(e) {
// 通过 MobX 提供的方法改变对应全局属性
this.updateActive(e.detail);
// 跳转到对应 tabBar页面
wx.switchTab({
url: this.data.list[e.detail].pagePath,
});
}
}
})
效果展示
替换 TabBar栏 选中颜色
通过 vant组件库提供的样式自定义属性,修改对应的颜色值 … >>>更多自定义样式属性介绍
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
active | 当前选中标签的索引 | number | – |
fixed | 是否固定在底部 | boolean | true |
placeholder | 固定在底部时,是否在标签位置生成一个等高的占位元素 | boolean | false |
border | 是否展示外边框 | boolean | true |
z-index | 元素 z-index | number | 1 |
active-color | 选中标签的颜色 | string | #1989fa |
inactive-color | 未选中标签的颜色 | string | #7d7e80 |
safe-area-inset-bottom | 是否为 iPhoneX 留出底部安全距离 | boolean | true |
代码演示
<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>
效果展示