Skip to content

一、自定义组件

注:小程序与vue的最大区别就是,vue的所有页面都是由组件构成的(只是有父组件和子组件之分),小程序的页面是由 页面+自定义组件 构成的

在小程序中,页面只是最外面的那一层,比重并不大!

页面和组件的区别:

页面是一个页面的大容器,相当于父组件,需要定义在app.json中

组件是页面的零部件,相当于子组件,不需要定义在app.json中

1.组件的创建与引用

1.1 创建组件

image-20221003174513789

本质上和页面的文件(数量和类型)是一样的

1.2 引用组件

image-20221003174543978

1.3 局部引用组件

image-20221003174601013

1.4 全局引用组件

image-20221003174617340

1.5 全局引用 VS 局部引用

image-20221003174631087

1.6 组件和页面的区别

image-20221003174647503

页面和组件的数据都是定义在data中的,但是页面的方法是直接定义,组件的方法是定义在methods中!

2.组件的样式

2.1 组件样式隔离

image-20221003174735060

组件样式隔离的注意点

image-20221003174758165

css
.class 属性值 {
	属性:值;
}

app.wxss的class选择器(仅限class选择器)的样式只对页面有效,对组件无效

2.2 修改组件的样式隔离选项

image-20221003174832016

styleIsolation 的可选值

可选值默认值描述
isolated表示启用样式隔离,在自定义组件内外,使用 class 指定的样式将不会相互影响(形成隔离)
apply-shared表示页面 wxss 样式将影响到自定义组件,但自定义组件 wxss 中指定的样式不会影响页面(页面——>组件)
shared表示页面 wxss 样式将影响到自定义组件,自定义组件 wxss 中指定的样式也会影响页面和其他设置了 apply-shared 或 shared 的自定义组件(页面<——>组件)

3.组件的数据、方法和属性

3.1 data 数据

image-20221003174950361

3.2 methods 方法

事件处理函数:用于和事件绑定

自定义方法:就是普通的函数,用_开头

image-20221003175004978

3.3 properties 属性

image-20221003175023249

和vue的prop类似,但是properties是可读可写的,和data一样

3.4 data 和 properties 的区别

image-20221003175039432

3.5 使用 setData 修改 properties 的值

image-20221003175055996

4.数据监听器

4.1 什么是数据监听器

注意:方法的参数值就是最新的字段值,这是默认获取的!!!

image-20221003175118536

4.2 数据监听器的基本用法:监听属性的变化

image-20221003175131362

可以监听data里面某些数据的变化,如果发生了变化就进行一系列逻辑:

image-20221003175145516

4.3 监听对象属性的变化

和监视普通属性其实没什么区别

image-20221003175157830

5.数据监听器 - 案例

5.1 案例效果

image-20221003175233719

注:这里的fullColor目前只是一个普通的字符串,后面可以用observers监视去实现一个计算属性的效果!

5.2 渲染 UI 结构

image-20221003175256033

5.3 定义 button 的事件处理函数

image-20221003175310102

5.4 监听对象中指定属性的变化

利用监视实现了计算属性

image-20221003175320975

5.5 监听对象中所有属性的变化:通配符

image-20221003175337964

6.纯数据字段

6.1 什么是纯数据字段

image-20221003175402056

不需要在页面上去显示的数据,只是运算的桥梁,就是纯数据字段

6.2 使用规则

image-20221003175419448

6.3 使用纯数据字段改造数据监听器案例

image-20221003175429417

7.组件的生命周期

7.1 组件全部的生命周期函数

image-20221003175458195

7.2 组件主要的生命周期函数

image-20221003175512919

attached最有用,类似于页面的onLoad生命周期函数!

7.3 lifetimes 节点

image-20221003175525944

8.组件所在页面的生命周期

8.1 什么是组件所在页面的生命周期

image-20221003175552115

8.2 pageLifetimes 节点

image-20221003175609489

8.3 生成随机的 RGB 颜色值

image-20221003175620290

Math.floor()函数:向下取整,最终得到的是[0,255]之间的数字

image-20221003175625913

show:用这个生命周期是因为这里是否生成随机颜色,是依赖于页面是否被展示

最终实现的效果:每次切到这个页面的时候(或者是最开始访问的时候),就会获取新的颜色!

9.插槽

9.1 什么是插槽

image-20221003175657185

即组件作为一个插槽函数,等待页面传入结构

9.2 定义单个插槽

image-20221003175715266

9.3 启用多个插槽

image-20221003175740835

9.4 定义多个插槽

image-20221003175759550

test4.wxml

html
<view>
  <slot name="before"></slot>
    <view>这里是组件的内部结构</view>
  <slot name="after"></slot>
</view>

9.5 使用多个插槽

image-20221003175817523

home.wxml

注意:这里不一定用view,任何标签都可以!

html
<my-test4>
  <view slot="before">这是通过插槽填充的内容</view>
  <view slot="after">~~~~~~~</view>
</my-test4>

10.父子组件之间的通信

10.1 父子组件之间通信的 3 种方式

注:这里不仅仅是组件,页面也可以是父组件!image-20221003175842646

10.2 属性绑定:父到子

image-20221003175857949

image-20221003175909781

10.3 事件绑定:子到父

image-20221003175928539

image-20221003175934292

注:sync是我们自定义的属性,可以任意,但是下面要用到

image-20221003175945113

image-20221003175954681

image-20221003180001890

代码:

test5.js

js
  methods: {
    addCount() {
      this.setData({
        count: this.properties.count + 1
      })
      // 触发自定义事件,将数值同步给父组件
      this.triggerEvent('sync', { value: this.properties.count })
    }
  }

home.js

js
  syncCount(e) {
    // console.log('syncCount')
    // console.log(e)
    // console.log(e.detail.value)
    this.setData({
      count: e.detail.value
    })
  },

10.4 获取组件实例

image-20221003180030612

test5.js

js
  methods: {
    addCount() {
      this.setData({
        count: this.properties.count + 1
      })
      // 触发自定义事件,将数值同步给父组件
      this.triggerEvent('sync', { value: this.properties.count })
    }
  }

home.js

js
getChild() {
    const child = this.selectComponent('#cA') //必须获取的是此页面应用的组件标签(test5组件)
    console.log(child)
    //可以用下面的方法,给子组件赋值,注意不能用this,只能用child
    // child.setData({
    //   count: child.properties.count + 1
    // })
    child.addCount() //调用子组件的addCount方法
}

home.wxml

html
<my-test5 count="{{count}}" bind:sync="syncCount" class="customA" id="cA"></my-test5>

注:本质上是在父组件中操控子组件中的数据,因为就算调用了子组件中的方法,也只能是操作子组件的数据,对父组件没什么影响!

但是子组件本身也是显示在父组件中的,所以也相当于操作了页面中的数据!

11.behaviors

11.1 什么是 behaviors?

image-20221003181246916

11.2 behaviors 的工作方式

image-20221003181303933

11.3 创建 behavior

image-20221003181320572

my-behavior.js

js
module.exports = Behavior({
  data: {
    username: 'zs'
  },
  properties: {},
  methods: {}
})

11.4 导入并使用 behavior

image-20221003181334616

test5.js

js
// components/test5/test5.js
const myBehavior = require('../../behaviors/my-behavior')

Component({
  behaviors: [myBehavior],
  /**
   * 组件的属性列表
   */
  properties: {
    count: Number
  },

  /**
   * 组件的初始数据
   */
  data: {
    username: 'ls'
  },

  /**
   * 组件的方法列表
   */
  methods: {
    addCount() {
      this.setData({
        count: this.properties.count + 1
      })
      // 触发自定义事件,将数值同步给父组件
      this.triggerEvent('sync', { value: this.properties.count })
    }
  }
})

11.5 behavior 中所有可用的节点

可用的节点类型是否必填描述
propertiesObject Map同组件的属性
dataObject同组件的数据
methodsObject同自定义组件的方法
behaviorsString Array引入其它的 behavior
createdFunction生命周期函数
attachedFunction生命周期函数
readyFunction生命周期函数
movedFunction生命周期函数
detachedFunction生命周期函数

11.6 同名字段的覆盖和组合规则

image-20221003181406607

https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/behaviors.html

如果冲突了,会比较复杂。

总结:

image-20221003181434334

二、使用 npm 包

1.小程序对 npm 的支持与限制

image-20221003224922098

但是npm还是可以用的!

2.Vant Weapp

2.1 什么是 Vant Weapp

image-20221003224953064

官方文档地址 https://youzan.github.io/vant-weapp

image-20221003231144855

2.2 安装 Vant 组件库

image-20221003225014970

https://youzan.github.io/vant-weapp/#/quickstart#an-zhuang

1.打开cmd窗口

image-20221003231341386

2.初始化一个package.json文件

bash
npm init -y

3.安装vant weapp

bash
npm i @vant/weapp@1.3.3 -S --production

4.构建npm包

image-20221003231636630

5.修改app.json

删除“style”:“v2”这个配置,否则可能样式冲突

注:还是要以官方文档为准!

2.3 使用 Vant 组件

image-20221003225026534

2.4 定制全局主题样式(使用 CSS 变量)

Vant Weapp 支持使用 CSS 变量来实现定制主题。

关于 CSS 变量的基本用法,请参考 MDN 文档:https://developer.mozilla.org/zh-CN/docs/Web/CSS/Using_CSS_custom_properties

有点类似于less,scss的操作,但是这是原生css的用法:css变量!

实际操作:

--加上变量名字即可组成为一个css变量名

在根节点page内定义css变量,这里面的变量是顶级作用域的

我们自己定义了css变量值,就可以覆盖Vant Weapp中默认的那个变量样式!

image-20221003225127182

所有Vant Weapp可用的颜色变量,请参考 Vant 官方提供的配置文件:https://github.com/youzan/vant-weapp/blob/dev/packages/common/style/var.less

3.API Promise化

3.1 基于回调函数的异步 API 的缺点

image-20221003225204388

3.2 什么是 API Promise 化

API Promise化 指的是:通过额外的配置,将官方提供的、基于回调函数的异步 API,升级改造为基于

Promise 的异步 API,从而提高代码的可读性、维护性,避免回调地狱的问题。

回调地域:回调函数中嵌套回调函数

Promise可以避免回调函数的嵌套

3.3 实现 API Promise 化

image-20221003225243286

在终端执行npm install --save miniprogram-api-promise@1.0.4(前提是已经有package.json这个文件了),然后点击构建npm(现在的版本好像不需要删除之前的miniprogramm_npm文件夹了)

强制删除的快捷键:选中要删除的文件,shift+delete即可

注:小程序中用npm安装完一个包之后都不能马上使用,需要点击构建npm才可以在小程序里面使用

image-20221004125642126

app.js

js
//app.js
import { promisifyAll } from 'miniprogram-api-promise'

const wxp = wx.p = {} //wxp是一个常量,wx.p是wx对象的一个属性,它们指向同一个空对象 ——> 连续赋值
promisifyAll(wx, wxp) //把wx对象上面的api都Promise化,然后挂载到wxp这个对象上面,然后可以通过wx.p去调用Promise的函数(因为wxp不是全局对象,所以只能用wx对象调用 ——>巧妙的设计)

App({
    //省略
})

3.4 调用 Promise 化之后的异步 API

image-20221003225254556

以前的网络请求:

js
Page({
    data: {
    },   
    getInfo() {
        wx.request({
            url: 'https://www.escook.cn/api/get',
            data: {
                name: 'zs',
                age: 20
            }
            method: 'get',
            success: ({ data: res }) => {
            this.setData({
                colorList: [...this.data.colorList, ...res.data]
            })
        },
            complete: () => {
                wx.hideLoading()
                this.setData({
                    isloding: false
                })
            }
    	})
	}
})

home.js

js
// pages/home/home.js
Page({
  data: {
  },
  async getInfo() {
    //{data: res}的意思是,结构返回的Promise对象的data属性,重命名为res(所以这里的res以及变味了,本来是Promise对象,现在是Promise对象的data属性,不过还需要再.data才是真正的数据)
    const {data: res} = await wx.p.request({ //wx.p.request的返回值是Promise对象,可以用async和await修饰,就不需要写回调函数了(不需要在success里面写,因为这个getInfo()方法本身就是一个异步的方法)
      method: 'GET',
      url: 'https://www.escook.cn/api/get',
      data: {
        name: 'zs',
        age: 20
      }
    })
    console.log(res)
    console.log(res.data)
  }
})

三、全局数据共享

1.简介

1.1 什么是全局数据共享

image-20221003225323879

1.2 小程序中的全局数据共享方案

需要两个包:一个用来定义store(包括数据和方法),一个用来把store中的数据和方法绑定到组件或者页面中使用

image-20221003225408825

2.MobX

2.1 安装 MobX 相关的包

image-20221003225432722
bash
npm install --save mobx-miniprogram@4.13.2 mobx-miniprogram-bindings@1.2.1

现在的版本好像不需要删除之前的miniprogramm_npm文件夹了

2.2 创建 MobX 的 Store 实例

在根目录下创建store文件夹,然后创建store.js文件

image-20221004133634355image-20221003225442703

store.js

js
// 在这个 JS 文件中,专门来创建 Store 的实例对象
// 按需导入相关方法
import { observable, action } from 'mobx-miniprogram'

export const store = observable({
  // 数据字段
  numA: 1,
  numB: 2,
  activeTabBarIndex: 0,
  // 计算属性:只有store里面可以定义计算属性,前面要加一个get修饰符,意味着这个属性是只读的
  // 这里是计算属性sum
  get sum() {
    return this.numA + this.numB //this指的就是store对象
  },
  // actions 函数:专门用来定义 用来修改 store 中数据的值 的方法
  updateNum1: action(function (step) { //updateNum1方法,用action包裹起来,作为action的参数
    this.numA += step
  }),
  updateNum2: action(function (step) { //updateNum2方法
    this.numB += step
  }),
  updateActiveTabBarIndex: action(function(index) { //updateActiveTabBarIndex方法
    this.activeTabBarIndex = index
  })
})

2.3 将 Store 中的成员绑定到页面中

image-20221003225501639

message.js

js
// pages/message/message.js
import { createStoreBindings } from 'mobx-miniprogram-bindings'
import { store } from '../../store/store'

Page({

  /**
   * 页面的初始数据
   */
  data: {

  },

  /**
   * 生命周期函数--监听页面加载:进行store的绑定
   */
  onLoad: function (options) {
    //createStoreBindings方法
    //第一个参数:this,代表页面Page的实例对象,意思是需要将store中的内容绑定给这个实例
    //第二个参数:需要绑定的内容,会直接绑定到Page对象上面
    //返回值为storeBindings,作为Page对象的属性,后面可以用于清理绑定关系
    this.storeBindings = createStoreBindings(this, { 
      store, //数据源,会把store的内容绑定到Page上
      fields: ['numA', 'numB', 'sum'], //绑定的字段,按需定义
      actions: ['updateNum1'] //绑定的方法,按需定义
    })
  },

  btnHandler1(e) {
    // console.log(e)
    // 直接调用我们绑定的store中的方法
    this.updateNum1(e.target.dataset.step) //e.target.dataset.xxx可以取到传入的事件函数的参数值
  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {
    this.storeBindings.detroyStoreBindings() //清理绑定的内容
  }
})

message.wxml

html
<!--pages/message/message.wxml-->
<view>{{numA}} + {{numB}} = {{sum}}</view>
<!--data-xxx为事件传参,step是自己定义的参数名-->
<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>

<view>~~~~~~</view>

<my-numbers></my-numbers>

2.4 在页面上使用 Store 中的成员

image-20221003225511993

2.5 将 Store 中的成员绑定到组件中

注:小程序中是页面和组件的store绑定方式完全不同的,自成一派!

image-20221003225524258

app.json 定义组件

json
"usingComponents": {
    "van-button": "@vant/weapp/button/index",
    "my-numbers": "./components/numbers/numbers",
    "van-tabbar": "@vant/weapp/tabbar/index",
    "van-tabbar-item": "@vant/weapp/tabbar-item/index"
}

message.xwml 使用组件

html
<!--pages/message/message.wxml-->
<view>{{numA}} + {{numB}} = {{sum}}</view>
<!--data-xxx为事件传参,step是自己定义的参数名-->
<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>

<view>~~~~~~</view>

<my-numbers></my-numbers> <!--使用my-numbers组件,默认显示的是组件路径-->

number.js

js
// components/numbers/numbers.js
import { storeBindingsBehavior } from 'mobx-miniprogram-bindings'//和Page中用的方法不一样
import { store } from '../../store/store'

Component({
  behaviors: [storeBindingsBehavior], //通过storeBindingsBehavior来实现自动绑定
  storeBindings: {
    store, //数据源
    fields: {
      // 映射的名字(任意):store中的名字
      numA: 'numA', //直接写字段名就可以了,最方便
      numB: 'numB',
      sum: 'sum'
    },
    actions: {
      updateNum2: 'updateNum2'
    }
  },

  /**
   * 组件的方法列表
   */
  methods: {
    btnHandler2(e) {
      this.updateNum2(e.target.dataset.step)
    }
  }
})

numbers.wxml

html
<!--components/numbers/numbers.wxml-->
<view>{{numA}} + {{numB}} = {{sum}}</view>
<van-button type="primary" bindtap="btnHandler2" data-step="{{1}}">numB + 1</van-button>
<van-button type="danger" bindtap="btnHandler2" data-step="{{-1}}">numB - 1</van-button>

2.6 在组件中使用 Store 中的成员

注:使用的方法在页面和组件中是一样的!

image-20221003225537038

四、分包

1.简介

1.1 什么是分包

分包指的是把一个完整的小程序项目,按照需求划分为不同的子包,在构建时打包成不同的分包,用户在使用时按需进行加载。

1.2 分包的好处

image-20221003225616882

比如每个人负责一个分包的开发,更加高效!

1.3 分包前项目的构成

image-20221003225631299

1.4 分包后项目的构成

image-20221003225645505

注:这里TabBar页面指的是可以通过TabBar跳转到的页面!

主包的公共资源可以被任意分包访问,但是分包的私有资源只有自己这个包才可以访问!

1.5 分包的加载规则

image-20221003225703742

类似于路由懒加载!

1.6 分包的体积限制

image-20221003225716440

如果使用了分包,所有分包不能超过16m,每个不能超过2m,但是仅限于分包,这个大小限制和主包无关

所以图片资源要很小才行,最好放在云端!

查看分包大小:

image-20221004141640753image-20221004141703612

注:据说新版的分包总大小限制变成了20m

2.使用分包

2.1 配置方法

image-20221003225739107

image-20221004141319196

app.json

json
{
  "pages": [
    "pages/home/home",
    "pages/message/message",
    "pages/contact/contact"
  ],
  "preloadRule": { //分包预下载
    "pages/contact/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 //独立分包
    }
  ],
  "window": {
    "backgroundTextStyle": "light",
    "navigationBarBackgroundColor": "#13A7A0",
    "navigationBarTitleText": "WeChat",
    "navigationBarTextStyle": "black"
  },
  "tabBar": { //这里面就是所有tabBar页面
    "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"
      }
    ]
  },
  "sitemapLocation": "sitemap.json",
  "usingComponents": {
    "van-button": "@vant/weapp/button/index",
    "my-numbers": "./components/numbers/numbers",
    "van-tabbar": "@vant/weapp/tabbar/index",
    "van-tabbar-item": "@vant/weapp/tabbar-item/index"
  }
}

2.2 打包原则

image-20221003225754289

2.3 引用原则

image-20221003225807002

3.独立分包

3.1 什么是独立分包

image-20221003225834661

3.2 独立分包和普通分包的区别

image-20221003225852989

3.3 独立分包的应用场景

image-20221003225906257

在只需要访问分包,不需要访问主包时,可以使用独立分包!

3.4 独立分包的配置方法

image-20221003225922322

3.5 引用原则

image-20221003225937440

4.分包预下载

4.1 什么是分包预下载

分包预下载指的是:在进入小程序的某个页面时,由框架自动预下载可能需要的分包,从而提升进入后续分包页面时的启动速度。

4.2 配置分包的预下载

image-20221003230014472

4.3 分包预下载的限制

image-20221003230029335

五、案例 - 自定义组件:tabBar

1.案例效果

image-20221003230105261

2.实现步骤

image-20221003230121717

https://developers.weixin.qq.com/miniprogram/dev/framework/ability/custom-tabbar.html

3.具体实现

1.app.json

“custom”: true 表示开启自定义tabBar

“list” 不用动,这些定义不会用于tabBar的渲染,但是为了低版本兼容和声明tabBar页面应当保留这个定义

image-20221004142518071

2.创建目录结构

注意:文件夹名和文件名都是固定的!在项目根目录下进行创建!

右键,新建组件,index组件

image-20221004142432888

小程序会自动读取这个目录下的内容,作为tabBar,自动渲染到页面的相应的位置

3.导入vant的tabBar组件

app.json

json
"usingComponents": {
    "van-button": "@vant/weapp/button/index",
    "my-numbers": "./components/numbers/numbers",
    "van-tabbar": "@vant/weapp/tabbar/index", //tabBar组件
    "van-tabbar-item": "@vant/weapp/tabbar-item/index" //tabBar组件
}

4.index.wxml

html
<!--custom-tab-bar/index.wxml-->
<!--active-color可以修改选中项的文本颜色值-->
<van-tabbar active="{{active}}" bind:change="onChange" active-color="#13A7A0">
    <!--info属性是图标右上角的数字标点的值,但是只有message需要这个值-->
	<van-tabbar-item wx:for="{{list}}" wx:key="index" info="{{item.info ? item.info : ''}}">
         <!--多个插槽:slot="icon"是未选中时的图标,slot="icon-active"是选中时的图标-->
		<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>

5.index.js

js
// custom-tab-bar/index.js
import { storeBindingsBehavior } from 'mobx-miniprogram-bindings'
import { store } from '../store/store'

Component({
  //修改样式作用域
  options: {
    styleIsolation: 'shared' //在自定义组件中,需要把作用域改为共享的,才可以去改写vant组件中的样式
  },
  //组件绑定store
  behaviors: [storeBindingsBehavior],
  storeBindings: {
    store,
    fields: { //绑定store中的数据
      sum: 'sum',
      active: 'activeTabBarIndex'
    },
    actions: { //绑定store中的方法
      updateActive: 'updateActiveTabBarIndex'
    },
  },
  //数据监听器
  observers: {
    'sum': function (val) { //监听sum数据,准备为info进行赋值,val是sum最新的值(自动获取的)
      this.setData({
        'list[1].info': val //赋值给info
      })
    }
  },

  /**
   * 组件的初始数据
   */
  data: {
    // active: 0, //要移到store中进行公共存储,否则每次用wx.switchTab跳转页面之后,active就会重新赋值为0了,那么图标和页面就不同步了
    "list": [ //根据list数组的数据去渲染每一个item项
      {
        "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",
        info: 0 //需要渲染数字徽标的项
      },
      {
        "pagePath": "/pages/contact/contact",
        "text": "联系我们",
        "iconPath": "/images/tabs/contact.png",
        "selectedIconPath": "/images/tabs/contact-active.png"
      }
    ]
  },

  /**
   * 组件的方法列表
   */
  methods: {
    //change事件绑定的函数
    onChange(event) {
      // event.detail(额外的信息)的值为当前选中项的tabBar索引(等价于在tabBar页面列表中的索引),用于给active重新赋值
      // this.setData({ active: event.detail })
      this.updateActive(event.detail); //更新索引值
      wx.switchTab({ //wx.switchTab方法可以进行页面的跳转!
        url: this.data.list[event.detail].pagePath, //event.detail就是tabBar索引,.pagePath得到的就是url
      })
    },
  }
})

6.index.wxss

css
/* custom-tab-bar/index.wxss */
.van-tabbar-item { /*在父节点上去定义变量(如果父节点有这个变量,子节点就可以直接用了)*/
  --tabbar-item-margin-bottom: 0; /*利用css变量修改vant的默认样式,让图标和文字间隙为0*/
}

7.store.js

js
// 在这个 JS 文件中,专门来创建 Store 的实例对象
import { observable, action } from 'mobx-miniprogram'

export const store = observable({
  // 数据字段
  numA: 1,
  numB: 2,
  activeTabBarIndex: 0,
  // 计算属性
  get sum() {
    return this.numA + this.numB
  },
  // actions 函数,专门来修改 store 中数据的值
  updateNum1: action(function (step) {
    this.numA += step
  }),
  updateNum2: action(function (step) {
    this.numB += step
  }),
  updateActiveTabBarIndex: action(function(index) { //用于自定义的tabBar使用,更新索引值
    this.activeTabBarIndex = index
  })
})

总结:

image-20221003230136504