目录
一、分包
链接: https://developers.weixin.qq.com/miniprogram/dev/framework/subpackages.html
1.分包加载
某些情况下,开发者需要将小程序划分成不同的子包,在构建时打包成不同的分包,用户在使用时按需进行加载。
在构建小程序分包项目时,构建会输出一个或多个分包。每个使用分包小程序必定含有一个主包。所谓的主包,即放置默认启动页面/TabBar 页面,以及一些所有分包都需用到公共资源/JS 脚本;而分包则是根据开发者的配置进行划分。
在小程序启动时,默认会下载主包并启动主包内页面,当用户进入分包内某个页面时,客户端会把对应分包下载下来,下载完成后再进行展示。
目前小程序分包大小有以下限制:
- 整个小程序所有分包大小不超过 20M;
- 单个分包/主包大小不能超过 2M。
对小程序进行分包,可以优化小程序首次启动的下载时间,以及在多团队共同开发时可以更好的解耦协作。
2.使用分包
链接: https://developers.weixin.qq.com/miniprogram/dev/framework/subpackages/basic.html
在 app.json 的subpackages 字段声明项目分包结构:
// app.json
{
"subpackages": [
{
"root": "packageA",
"name": "pkA",
"pages": [
"pages/a1/a1",
"pages/a2/a2"
]
},
{
"root": "packageB",
"name": "pkB",
"pages": [
"pages/b1/b1",
"pages/b2/b2"
]
}
],
}
1.打包原则
- 声明 subpackages 后,将按 subpackages 配置路径进行打包,subpackages 配置路径外的目录将被打包到主包中;
- 主包也可以有自己的 pages,即最外层的 pages 字段;
- subpackage 的根目录不能是另外一个 subpackage 内的子目录;
- tabBar 页面必须在主包内。
注:
- 主包不能访问分包的私有资源;
- 分包之间不能相互引用私有资源;
- 分包可以引用主包内的公共资源。
2.独立分包
用户打开小程序,先下载主包,展示主包内的页面。从主包跳到分包页面时下载分包资源。用户想进入分包页面,需要先下载主包,在下载分包。
特殊情况: 用户要直接进入分包页面,只下载分包:使用独立分包。链接: https://developers.weixin.qq.com/miniprogram/dev/framework/subpackages/independent.html
独立分包是小程序中一种特殊类型的分包,可以独立于主包和其他分包运行。从独立分包中页面进入小程序时,不需要下载主包。当用户进入普通分包或主包内页面时,主包才会被下载。
开发者可以按需将某些具有一定功能独立性的页面配置到独立分包中。当小程序从普通的分包页面启动时,需要首先下载主包;而独立分包不依赖主包即可运行,可以很大程度上提升分包页面的启动速度。
一个小程序中可以有多个独立分包。
通过在app.json的subpackages字段中对应的分包配置项中定义independent字段声明对应分包为独立分包。
// app.json
{
"subpackages": [
{
"root": "packageA",
"name": "pkA",
"pages": [
"pages/a1/a1",
"pages/a2/a2"
]
"independent": true
}
]
}
3.限制
独立分包属于分包的一种。普通分包的所有限制都对独立分包有效。独立分包中插件、自定义组件的处理方式同普通分包。此外,使用独立分包时要注意:
- 独立分包中不能依赖主包和其他分包中的内容,包括 js 文件、template、wxss、自定义组件、插件等(使用 分包异步化 时 js 文件、自定义组件、插件不受此条限制);
- 主包中的 app.wxss 对独立分包无效,应避免在独立分包页面中使用 app.wxss 中的样式;
- App 只能在主包内定义,独立分包中不能定义 App,会造成无法预期的行为;
- 独立分包中暂时不支持使用插件。
3.分包预下载
链接: https://developers.weixin.qq.com/miniprogram/dev/framework/subpackages/preload.html
开发者可以通过配置,在进入小程序某个页面时,由框架自动预下载可能需要的分包,提升进入后续分包页面时的启动速度。对于独立分包,也可以预下载主包。
分包预下载目前只支持通过配置方式使用,暂不支持通过调用API完成。
预下载分包行为在进入某个页面时触发,通过在 app.json 增加 preloadRule 配置来控制。
{
"subpackages": [
{
"root": "packageA",
"pages": [
"pages/a1/a1",
"pages/a2/a2"
],
},
"preloadRule": {
"pages/home/home":{
"network": "wifi" // all
"packages": ["packageA"]
}
}
}
分包预下载提示:
限制
同一个分包中的页面享有共同的预下载大小限额 2M,限额会在工具中打包时校验。
如,页面 A 和 B 都在同一个分包中,A 中预下载总大小 0.5M 的分包,B中最多只能预下载总大小 1.5M 的分包。
二、自定义tabbar案例
1.配置
链接: https://developers.weixin.qq.com/miniprogram/dev/framework/ability/custom-tabbar.html
该自定义tabbar需要先配置相关npm包和vant weapp框架,具体参照前几节。
在自定义 tabBar 模式下
为了保证低版本兼容以及区分哪些页面是 tab 页,tabBar 的相关配置项需完整声明,但这些字段不会作用于自定义 tabBar 的渲染。
此时需要开发者提供一个自定义组件来渲染 tabBar,所有 tabBar 的样式都由该自定义组件渲染。推荐用 fixed 在底部的 cover-view + cover-image 组件渲染样式,以保证 tabBar 层级相对较高。
与 tabBar 样式相关的接口,如 wx.setTabBarItem 等将失效。
每个 tab 页下的自定义 tabBar 组件实例是不同的,可通过自定义组件下的 getTabBar 接口,获取当前页面的自定义 tabBar 组件实例。
先配置默认的tabbar页面,当自定义页面未显示时默认为配置的tabbar页面:
// app.json
{
"pages":[
"pages/home/home",
"pages/categories/categories",
"pages/cart/cart",
"pages/me/me"
],
"subpackages": [
{
"root": "packageA",
"name": "pkA",
"pages": [
"pages/a1/a1",
"pages/a2/a2"
]
},
{
"root": "packageB",
"name": "pkB",
"pages": [
"pages/b1/b1",
"pages/b2/b2"
],
"independent": true
}
],
"preloadRule": {
"pages/home/home":{
"network": "all",
"packages": ["packageA"]
}
},
"window":{
"backgroundTextStyle":"light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "Weixin",
"navigationBarTextStyle":"black"
},
"tabBar": {
"custom": true,
"list": [
{
"pagePath": "pages/home/home",
"text": "首页",
"iconPath": "/images/tabbarhome.png",
"selectedIconPath": "/images/tabbarhome-active.png"
},
{
"pagePath": "pages/categories/categories",
"text": "分类",
"iconPath": "/images/tabbar.png",
"selectedIconPath": "/images/tabbar-active.png"
},
{
"pagePath": "pages/cart/cart",
"text": "购物车",
"iconPath": "/images/icontabbarshoppingup.png",
"selectedIconPath": "/images/icontabbarshoppingup-active.png"
},
{
"pagePath": "pages/me/me",
"text": "我的",
"iconPath": "/images/icontabbarmyup.png",
"selectedIconPath": "/images/icontabbarmyup-active.png"
}
]
},
"sitemapLocation": "sitemap.json"
}
2. 配置信息
1.在 app.json 中的 tabBar 项指定 custom 字段,同时其余 tabBar 相关配置也补充完整。
"tabBar": {
**加粗样式** "custom": true,
}
2. 添加 tabBar 代码文件
在代码根目录下添加入口文件:
custom-tab-bar/index.js
custom-tab-bar/index.json
custom-tab-bar/index.wxml
custom-tab-bar/index.wxss
在custom-tab-bar文件夹右键新建components:
在index.wxml中输入内容,会显示在tabbar区域:
3.引入
在app.json中引入组件,详细介绍见链接: https://vant-contrib.oschina.io/vant-weapp/#/quickstart#yin-ru-zu-jian。
"usingComponents": {
"van-tabbar": "@vant/weapp/tabbar/index",
"van-tabbar-item": "@vant/weapp/tabbar-item/index"
}
基础用法:
代码演示:
<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>
// custom-tab-bar/index.js
Component({
data: {
active: 0, //当前选中的item下标
},
methods: {
onChange(event) {
// event.detail 的值为当前选中项的索引
this.setData({ active: event.detail });
},
}
})
active: 0 表示默认状态下被选中的tabbar图标,0表示第一个图标;
当点击非默认图标时,调用onChange()方法更改active的值。
1.自定义图标
可以通过 slot 自定义图标,其中 icon slot 代表未选中状态下的图标,icon-active slot 代表选中状态下的图标。
<!--custom-tab-bar/index.wxml-->
<van-tabbar active="{{ active }}" bind:change="onChange">
<van-tabbar-item>
<image
slot="icon"
src="/images/tabbarhome.png"
mode="aspectFit"
style="width: 30px; height: 18px;"
/>
<image
slot="icon-active"
src="/images/tabbarhome-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>
第一个图标发生改变,成为自定义图标:
遍历写法:
先在js中定义要循环的数组list:
// custom-tab-bar/index.js
Component({
data: {
active: 0,
"list": [
{
"pagePath": "pages/home/home",
"text": "首页",
"iconPath": "/images/tabbarhome.png",
"selectedIconPath": "/images/tabbarhome-active.png"
},
{
"pagePath": "pages/categories/categories",
"text": "分类",
"iconPath": "/images/tabbar.png",
"selectedIconPath": "/images/tabbar-active.png"
},
{
"pagePath": "pages/cart/cart",
"text": "购物车",
"iconPath": "/images/icontabbarshoppingup.png",
"selectedIconPath": "/images/icontabbarshoppingup-active.png"
},
{
"pagePath": "pages/me/me",
"text": "我的",
"iconPath": "/images/icontabbarmyup.png",
"selectedIconPath": "/images/icontabbarmyup-active.png"
}
]
},
methods: {
onChange(event) {
// event.detail 的值为当前选中项的索引
this.setData({ active: event.detail });
},
}
})
<!--custom-tab-bar/index.wxml-->
<van-tabbar active="{{ active }}" bind:change="onChange">
<van-tabbar-item wx:for="{{list}}" wx:key="index">
<image
slot="icon"
src="{{item.iconPath}}"
mode="aspectFit"
style="width: 30px; height: 18px;"
/>
<image
slot="icon-active"
src="{{item.selectedIconPath}}"
mode="aspectFit"
style="width: 30px; height: 18px;"
/>
{{item.text}}
</van-tabbar-item>
</van-tabbar>
2.更改文字样式
可通过调试器找到文字颜色的样式,然后通过css进行样式覆盖:https://vant-contrib.oschina.io/vant-weapp/#/custom-style
3.自定义颜色
链接: https://vant-contrib.oschina.io/vant-weapp/#/tabbar
<van-tabbar
active-color="#f00" // 被选中时的颜色
inactive-color="#00f" // 默认时的颜色
>
</van-tabbar>
4.显示徽标
通过info=" "字段进行显示,若直接在定义,则所有tabbar都会出现徽标:
// custom-tab-bar/index.js
Component({
data: {
active: 0,
"list": [
{
"pagePath": "pages/home/home",
"text": "首页",
"iconPath": "/images/tabbarhome.png",
"selectedIconPath": "/images/tabbarhome-active.png",
"info": 5
},
]
},
})
<van-tabbar-item wx:for="{{list}}" wx:key="index"
info="{{item.info}}">
</van-tabbar-item>
a.更改徽标颜色
先在wxml结构中找到徽标的颜色属性:
进行覆盖:
/* custom-tab-bar/index.wxss */
.van-info{
background-color: #66ff7a
}
在组件中进行样式覆盖需要开启声明:styleIsolation: “shared”
Component({
options:{
styleIsolation: "shared"
},
})
b.动态info徽标
1.设计wxml页面: 这里假设有两个商品,分别设置按钮对商品进行数量的加减,每次加减通过参数data-step传入。使用van weapp按钮记得在app.json中声明:
{
"usingComponents": {
"van-button": "@vant/weapp/button/index"
}
}
<!--pages/home/home.wxml-->
<text>pages/home/home.wxml</text>
<view>商品列表:</view>
<view>
¥ 3999 数量:
<van-button type="info" bindtap="changePhoneNum" data-step="{{1}}">+</van-button>
{{goodsNum1}}
<van-button type="danger" bindtap="changePhoneNum" data-step="{{-1}}">-</van-button>
</view>
<view>---------------</view>
<view>
¥ 7999 数量:
<van-button type="info" bindtap="changeTaptopNum" data-step="{{1}}">+</van-button>
{{goodsNum2}}
<van-button type="danger" bindtap="changeTaptopNum" data-step="{{-1}}">-</van-button>
</view>
2.设计js页面的数量变化:
在页面导入store mobx数据以获取商品的数量变化,设计方法使得点击按钮时发生数量改变。
// pages/home/home.js
// 导入store mobx数据仓库
import {store} from "../../store/store"
// 使用bindings包搭建页面与数据仓库之间的桥梁
import {createStoreBindings} from "mobx-miniprogram-bindings";
Page({
onLoad(options) {
// 绑定mobx store对象
// 第一个参数为将数据绑定到的地方,如此处为该页面
// 第二个参数为要绑定的数据
this.storeBindings = createStoreBindings(this, {
store: store, // 指定store为数据源
fields: ["goodsNum1", "goodsNum2", "goodsSum"], // 将store中需要使用的数据映射到页面的this.data中
actions: ["updataGoodsNum1", "updataGoodsNum2"], // 将store中需要使用到的action方法映射到页面
});
//console.log(this);
},
changePhoneNum(e){
this.updataGoodsNum1(e.target.dataset.step);
},
changeTaptopNum(e){
this.updataGoodsNum2(e.target.dataset.step);
},
// 生命周期函数:监听页面卸载
onUnload: function(){
// 清理工作
this.storeBindings.destroyStoreBindings(); // 解绑mobx数据对象
}
})
3.配置store mobx共享数据仓库:
这里有两个商品,则设计两个数据字段goodsNum1、goodsNum2;计算属性为商品总数goodsSum;使用actio函数修改每个商品的数量(限制数量最小为1)。
// store.js
// 创建mobx store实例对象(共享的数据仓库)
// 导入
// 如果要使用action函数修改数据,需要在导入时加入action字段
import {action, observable} from "mobx-miniprogram"
// 导出
export const store = observable({
// 数据字段
goodsNum1: 1,
goodsNum2: 1,
// 计算属性:商品总数
get goodsSum(){
return this.goodsNum1 + this.goodsNum2;
},
// 修改商品数量
updataGoodsNum1: action(function(val){
// 限制最小数量为1
if(this.goodsNum1 + val < 1){
this.goodsNum1 = 1;
}else{
this.goodsNum1 += val;
}
}),
updataGoodsNum2: action(function(val){
// 限制最小数量为1
if(this.goodsNum2 + val < 1){
this.goodsNum2 = 1;
}else{
this.goodsNum2 += val;
}
})
});
4.在自定义tabbar(组件)导入store mobx:
配置对象所需的数据字段只需要商品总数即可,通过数据监听商品总数goodsSum,当其发生改变时,通过参数newVal获取其新值,再将新值赋予之前定义好的徽标变量info。
// custom-tab-bar/index.js
// 导入store mobx数据仓库
import {store} from "../store/store"
// 使用bindings包搭建页面与数据仓库之间的桥梁
import {storeBindingsBehavior} from "mobx-miniprogram-bindings";
Component({
// 在behaviors添加storeBindingsBehavior来做绑定功能
behaviors: [storeBindingsBehavior],
// 配置对象
storeBindings: {
store: store, //指定要绑定的数据源
fields: {
goodsSum: "goodsSum",
},
},
// 数据监听
observers:{
"goodsSum":function(newVal){
this.setData({
"list[2].info": newVal
})
}
},
})
5.跳转tabbar页面
注意页面路径要以"/"开头。
// custom-tab-bar/index.js
Component({
methods: {
onChange(event) {
// event.detail 的值为当前选中项的索引
this.setData({ active: event.detail });
// 跳转tabbar页面
wx.switchTab({
url: this.data.list[event.detail].pagePath,
})
},
}
})
6.优化默认选中的tabbar下标
原因:index.js中定义的默认下标active是非动态的,导致选中其他tabbar的item时会发生错误,即页面跳转了,但item效果未变。(图标未变,文字颜色未变)
定义下标字段和方法:tabBarIndex、updataTabBarIndex
// store.js
// 创建mobx store实例对象(共享的数据仓库)
// 导入
// 如果要使用action函数修改数据,需要在导入时加入action字段
import {action, observable} from "mobx-miniprogram"
// 导出
export const store = observable({
// 数据字段
tabBarIndex: 0, //当前tabbar选中的item下标
// 修改tabbar选中的item下标
updataTabBarIndex: action(function(index){
this.tabBarIndex = index;
})
});
在tabbar组件中导入所需的数据字段和action修改方法:
active: “tabBarIndex” 和 actions:{updataTabBarIndex: “updataTabBarIndex”}
// custom-tab-bar/index.js
// 导入store mobx数据仓库
import {store} from "../store/store"
// 使用bindings包搭建页面与数据仓库之间的桥梁
import {storeBindingsBehavior} from "mobx-miniprogram-bindings";
Component({
// 在behaviors添加storeBindingsBehavior来做绑定功能
behaviors: [storeBindingsBehavior],
// 配置对象
storeBindings: {
store: store, //指定要绑定的数据源
fields: {
active: "tabBarIndex" // 存在mobx里的下标
},
actions:{
updataTabBarIndex: "updataTabBarIndex"
}
},
data: {
active: 0,
},
methods: {
onChange(event) {
// event.detail 的值为当前选中项的索引
this.setData({ active: event.detail });//
// 跳转tabbar页面
wx.switchTab({
url: this.data.list[event.detail].pagePath,
}),
// 将当前tabbar的下标值传入store,并更新为选中的下标
this.updataTabBarIndex(event.detail);
},
}
})
4.完整代码
<!--pages/home/home.wxml-->
<text>pages/home/home.wxml</text>
<view>商品列表:</view>
<view>
¥ 3999 数量:
<van-button type="info" bindtap="changePhoneNum" data-step="{{1}}">+</van-button>
{{goodsNum1}}
<van-button type="danger" bindtap="changePhoneNum" data-step="{{-1}}">-</van-button>
</view>
<view>---------------</view>
<view>
¥ 7999 数量:
<van-button type="info" bindtap="changeTaptopNum" data-step="{{1}}">+</van-button>
{{goodsNum2}}
<van-button type="danger" bindtap="changeTaptopNum" data-step="{{-1}}">-</van-button>
</view>
// pages/home/home.js
// 导入store mobx数据仓库
import {store} from "../../store/store"
// 使用bindings包搭建页面与数据仓库之间的桥梁
import {createStoreBindings} from "mobx-miniprogram-bindings";
Page({
onLoad(options) {
// 绑定mobx store对象
// 第一个参数为将数据绑定到的地方,如此处为该页面
// 第二个参数为要绑定的数据
this.storeBindings = createStoreBindings(this, {
store: store, // 指定store为数据源
fields: ["goodsNum1", "goodsNum2", "goodsSum"], // 将store中需要使用的数据映射到页面的this.data中
actions: ["updataGoodsNum1", "updataGoodsNum2"], // 将store中需要使用到的action方法映射到页面
});
//console.log(this);
},
changePhoneNum(e){
this.updataGoodsNum1(e.target.dataset.step);
},
changeTaptopNum(e){
this.updataGoodsNum2(e.target.dataset.step);
},
// 生命周期函数:监听页面卸载
onUnload: function(){
// 清理工作
this.storeBindings.destroyStoreBindings(); // 解绑mobx数据对象
}
})
<!--custom-tab-bar/index.wxml-->
<van-tabbar active="{{ active }}" bind:change="onChange" active-color="#f00" inactive-color="#00f">
<van-tabbar-item wx:for="{{list}}" wx:key="index" info="{{item.info}}">
<image
slot="icon"
src="{{item.iconPath}}"
mode="aspectFit"
style="width: 30px; height: 18px;"
/>
<image
slot="icon-active"
src="{{item.selectedIconPath}}"
mode="aspectFit"
style="width: 30px; height: 18px;"
/>
{{item.text}}
</van-tabbar-item>
</van-tabbar>
// custom-tab-bar/index.js
// 导入store mobx数据仓库
import {store} from "../store/store"
// 使用bindings包搭建页面与数据仓库之间的桥梁
import {storeBindingsBehavior} from "mobx-miniprogram-bindings";
Component({
// 在behaviors添加storeBindingsBehavior来做绑定功能
behaviors: [storeBindingsBehavior],
// 配置对象
storeBindings: {
store: store, //指定要绑定的数据源
fields: {
goodsSum: "goodsSum",
active: "tabBarIndex" // 存在mobx里的下标
},
actions:{
updataTabBarIndex: "updataTabBarIndex"
}
},
// 数据监听
observers:{
"goodsSum":function(newVal){
this.setData({
"list[2].info": newVal
})
}
},
options:{
styleIsolation: "shared"
},
data: {
active: 0,
"list": [
{
"pagePath": "/pages/home/home",
"text": "首页",
"iconPath": "/images/tabbarhome.png",
"selectedIconPath": "/images/tabbarhome-active.png",
},
{
"pagePath": "/pages/categories/categories",
"text": "分类",
"iconPath": "/images/tabbar.png",
"selectedIconPath": "/images/tabbar-active.png"
},
{
"pagePath": "/pages/cart/cart",
"text": "购物车",
"iconPath": "/images/icontabbarshoppingup.png",
"selectedIconPath": "/images/icontabbarshoppingup-active.png",
"info": 0
},
{
"pagePath": "/pages/me/me",
"text": "我的",
"iconPath": "/images/icontabbarmyup.png",
"selectedIconPath": "/images/icontabbarmyup-active.png"
}
]
},
methods: {
onChange(event) {
// event.detail 的值为当前选中项的索引
this.setData({ active: event.detail });
// 跳转tabbar页面
wx.switchTab({
url: this.data.list[event.detail].pagePath,
}),
// 将当前tabbar的下标值存入store,并更新为选中的下标
this.updataTabBarIndex(event.detail);
},
}
})
// store.js
// 创建mobx store实例对象(共享的数据仓库)
// 导入
// 如果要使用action函数修改数据,需要在导入时加入action字段
import {action, observable} from "mobx-miniprogram"
// 导出
export const store = observable({
// 数据字段
goodsNum1: 1,
goodsNum2: 1,
tabBarIndex: 0, //当前tabbar选中的item下标
// 商品总数
get goodsSum(){
return this.goodsNum1 + this.goodsNum2;
},
// 修改商品数量
updataGoodsNum1: action(function(val){
// 限制最小数量为1
if(this.goodsNum1 + val < 1){
this.goodsNum1 = 1;
}else{
this.goodsNum1 += val;
}
}),
updataGoodsNum2: action(function(val){
// 限制最小数量为1
if(this.goodsNum2 + val < 1){
this.goodsNum2 = 1;
}else{
this.goodsNum2 += val;
}
}),
// 修改tabbar选中的item下标
updataTabBarIndex: action(function(index){
this.tabBarIndex = index;
})
});