前端|微信小程序 - 进阶(自定义组件、promis化、mobx、分包、自定义tabBar)


文章目录

    • 一、自定义组件
      • 1、创建组件
      • 2、引用组件
      • 3、组件和页面区别
      • 4、组件样式
      • 5、data、methods、properties
      • 6、小程序的 data 和 properties 区别
      • 7、数据监听器(observers )
      • 8、纯数据字段(pureDataPattern)
      • 9、组件的生命周期(lifetimes)
      • 10、组件所在页面生命周期(pageLifetimes )
      • 11、插槽
      • 12、父子组件数据传递(properties 、triggerEvent())
      • 13、behaviors(混入)
    • 二、使用 npm 包
      • 1、Vant Weapp
      • 2、css变量定制样式
    • 三、小程序 API 的 Promise 化
      • 1、为什么要 Pronise 化
      • 2、实现 Promise 化
      • 3、调用 Promise 化的 API
    • 四、全局数据共享(mobx-miniprogram、mobx-miniprogram-bindings )
      • 1、什么是全局数据共享
      • 2、创建 Store 实例对象
      • 3、在页面中使用 Store(createStoreBindings )
      • 4、在组件中使用(storeBindingsBehavior)
    • 五、分包(subpackages )
      • 1、分包后规则
      • 2、分包基本用法
      • 3、打包原则
      • 4、引用原则
      • 5、独立分包(independent)
      • 6、分包预下载(preloadRule)
    • 六、自定义 tabBar
      • 1、配置

一、自定义组件 参考:自定义组件
1、创建组件
1、在根目录新建文件夹 components ,然后在 components 文件夹下新建组件文件夹 test ;在 test 文件夹右键点击新建Component,输入组件名称 test 之后会生成对应的 4 个文件:test.js、test.json、test.wxml、test.wxss;
2、引用组件
1、全局引用:在 app.json 全局配置文件中引入组件,在 window 同级新增下面配置
{ "pages":[], "winodw":{}, "usingComponents": { "test":"/components/test/test" } }

2、局部引用:在页面的 .json 文件中引入组件
{ "usingComponents": { "test":"/components/test/test" } }

使用:在页面 wxml 文件中直接使用

3、组件和页面区别
1、组件的 .json 文件中需要声明 “component”: true;
2、组件的 .js 文件中调用的是 Component({}) 函数;
3、组件的事件处理函数要定义到 methods 节点上;
4、组件样式
1、组件样式隔离:组件之间的样式互不影响,组件和页面的样式也是相对独立的;这也可以防止组件和页面之间样式污染;
注意:
1、由于组件的样式隔离在 app.wxss 中定义的全局样式对组件是无效的;
2、只有 class 选择器会被隔离,id选择器、属性选择器、标签选择器不受样式隔离影响;
2、修改样式隔离选项
在组件中通过 stylelsolation 修改组件的样式隔离选项
Component({ options:{ stylelsolation : isolated } })

或者在组件的 .json 文件中配置
{ "component": true, "stylelsolation": "isolated", "usingComponents": {} }

isolated:开启样式隔离
apply-shared:页面样式会影响到组件,但是组件的样式不会影响到页面
shared:页面样式会影响到组件,组件的样式也会影响到其他页面和设置为 shared、apply-shared 的组件
5、data、methods、properties
1、data:组件的私有数据;
2、methods:组件的事件处理函数和自定义方法都放在这里,自定义方法建议下划线开头,与事件处理函数区分开;
3、properties:用来接收外界传递到组件中的数据;

//data平级 properties: { //完整格式 min:{ type:Number, //类型 value:10 //默认值 } //简写 min:Number //类型 }

获取 properties 传递的数据可以直接 this.properties.min 来获取;
6、小程序的 data 和 properties 区别
跟 vue 的不同,小程序的 data 和 properties 都是可读可写的;在组件里面可以对 properties 传递进来的对象重新赋值,这一点和 vue 里面的 props 是不一样的; data 和 properties的侧重点不一样:data 侧重组件私有数据,properties 侧重外界传递的数据;
data 和 properties 在本质上是一样的东西,只是认为的区分了他们的功能;所以对于 properties 的操作很操作 data 的方式是一样的(读取、修改);
7、数据监听器(observers )
数据监听器用于监听和响应属性和数据的变化,从而执行特定的操作;类似 vue 里面的 watch ;小程序的语法如下:
1、observers 可以一次监听多个对象,中间逗号隔开,在function的参数中对应的是对象的最新值
//data平级 observers: { 'numberA, numberB': function(newNumberA, newNumberB) { // 在 numberA 或者 numberB 被设置时,执行这个函数 this.setData({ sum: newNumberA+ newNumberB }) } }

2、observers 还可以监听对象的属性值
//data平级 observers: { 'numberA.value, numberB.value': function(newNumberA, newNumberB) { // 在 numberA 或者 numberB 被设置时,执行这个函数 this.setData({ sum: newNumberA + newNumberB }) } }

3、监听对象中所以属性的变化,可以使用通配符 “**”
//data平级 observers: { 'obj.**': function(obj) { console.log(obj); } }

只要 obj 里面的属性发生变化就会触发监听;
8、纯数据字段(pureDataPattern)
纯数字字段:指的是那些不用于界面渲染的 data 数据,也不会传递给其他组件,仅在当前组件内部使用;
好处:有助于提升页面更新的性能;
1、设置纯数据字段
在组件的 Cpmponent 函数中的 options 节点,指定 pureDataPattern 为一个正则表达式,字段名符合这个规则的将成为纯数据字段;
Component({ options: { pureDataPattern: /^_/ // 指定所有 _ 开头的数据字段为纯数据字段 }, data: { a: true, // 普通数据字段 _b: true, // 纯数据字段 }, methods: { myMethod() { this.data._b // 纯数据字段可以在 this.data 中获取 this.setData({ c: true, // 普通数据字段 _d: true, // 纯数据字段 }) } } })

9、组件的生命周期(lifetimes)
1、小程序很神奇,它的组件生命周期跟页面生命周期(onLoad、onReady、onShow、onHide、onUnload)和应用生命周期(onLaunch、onShow、onHide)完全不一样:
created:在组件实例刚刚被创建时执行,还不能调用 setData,只能给组件的 this 添加一些自定义的属性字段;
attached:在组件实例进入页面节点树时执行,还未渲染,this.data 已经初始化完毕,可以做一些初始化工作(发请求获取初始化数据);
ready:在组件在视图层布局完成后执行,刚被渲染完成之后;
moved:在组件实例被移动到节点树另一个位置时执行;
detached:在组件实例被从页面节点树移除时执行,适合做一些清理性质的工作;
error:每当组件方法抛出错误时执行;
2、定义生命周期函数:将生命周期函数定义在 lifetimes(最新-建议) 字段内
Component({ lifetimes: { attached: function() { // 在组件实例进入页面节点树时执行 }, detached: function() { // 在组件实例被从页面节点树移除时执行 }, } })

10、组件所在页面生命周期(pageLifetimes )
1、由于组件的某些行为会依赖页面的状态变化,所有需要在组件的 js 文件中监听页面的变化,这种可以被组件访问的生命周期就是 组件所在页面的生命周期;
show:组件所在的页面被展示时执行
hide:组件所在的页面被隐藏时执行
resize:组件所在的页面尺寸变化时执行
2、定义生命周期:必须定义在 pageLifetimes 节点中;
Component({ pageLifetimes: { show: function() { // 页面被展示 }, hide: function() { // 页面被隐藏 }, resize: function(size) { // 页面尺寸变化 } } })

11、插槽
1、单个插槽:跟 vue 里面插槽差不多,也是占位符的作用;小程序中默认每个自定义组件只能使用一个插槽 占位
//组件 test 这是一个组件 //对于不确定的内容,使用 slot 占位,具体内容由组件的使用者决定 > //调用 这个内容会渲染到插槽位置

2、启用多个插槽:小程序中如果想使用多个插槽,需要在组件中进行配置
Component({ options: { multipleSlots: true // 组件使用多 slot } })

多个插槽需要给 slot 定义一个 name 来区分
//组件 test ="head"> 这是一个组件 //对于不确定的内容,使用 slot 占位,具体内容由组件的使用者决定 ="foot"> //调用 这是头部的内容 这是底部的内容

12、父子组件数据传递(properties 、triggerEvent())
1、属性绑定
父组件向子组件的指定属性设置数据,仅能设置 JSON 兼容的数据,无法传递方法;
子组件在 properties 节点上声明对应的属性并使用:
//子组件 properties: { min:{ type:Number, value:0 } } //父组件

子组件可以对 properties 的属性值进行修改,但是不会直接传递给父组件,如果想传递给父组件就需要用到下面的方法:
2、事件绑定
子组件向父组件传递数据,可以传递任何数据;
父组件 js 文件中定义事件,并在 wxml 文件中绑定事件,子组件调用 this.triggerEvent(事件名,参数) 函数将数据发送给父组件,然后父组件中通过 e.detail 获取到数据:
//父组件 js,定义一个方法接收子组件通过info事件传递的值 getChildInfo(e){ console.log(e.detail); } //父组件 wxml,定义一个方法 info 给子组件使用 //还可以这样绑定,不过推荐使用上面那种 //子组件传值,在btn 点击事件中传值整个 data btn(){ this.triggerEvent("info",this.data) }

这个流程跟 vue 的子组件传值给父组件其实是差不多的;
3、获取组件实例
父组件可以通过 this.selectComponent() 方法获取子组件的实例,这也可以访问子组件的任何数据和方法;this.selectComponent() 方法接收一个选择器(id、class),不可以使用其他选择器;
//wxml //js onLoad: function (options) { const testChild = this.selectComponent('.test') console.log(testChild) testChild.setData({num:1}); //调用子组件的setDate方法修改数据 testChild.test(); //调用子组件的方法 }

这样就可以在父组件里面访问子组件的数据、调用子组件的方法(也可以调用子组件的 setData 方法来修改数据);
13、behaviors(混入)
是小程序中用于实现代码共享的一个方式,类似于 vue 中的 mixins ;每个 behaviors 都有自己的属性、数据、生命周期函数、方法,组件引用它的时候这些属性、数据、方法会被合并到组件中;
每个组件都有可以引入多个 behaviors,behaviors之间也可以相互引用;
1、创建 behaviors
调用 Behaviors 方法就可以创建一个共享的 behaviors 实例对象,供所有组件使用:根目录创建 behaviors 文件夹,然后创建一个 test.js
module.exports = Behaviors({ data:{}, properties:{}, methods:{} })

2、导入和使用
在组件中使用 behaviors ,使用 require() 方法来引入,挂载之后就可以使用 behaviors 中提供的数据和方法;
//导入 const test = require("../../behavior/test"); //挂载,可挂载多个,逗号隔开 Component({ behaviors:[test] })

3、behaviors 与组件优先级
data:
若同名的数据字段都是对象类型,会进行对象合并
其余情况会进行数据覆盖,覆盖规则为:组件 > 父 behavior > 子 behavior 、 靠后的 behavior > 靠前的 behavior。(优先级高的覆盖优先级低的,最大的为优先级最高)
properties 、methods:
若组件本身有这个属性或方法,则组件的属性或方法会覆盖 behavior 中的同名属性或方法
若组件本身无这个属性或方法,则在组件的 behaviors 字段中定义靠后的 behavior 的属性或方法会覆盖靠前的同名属性或方法;
若存在嵌套引用 behavior 的情况,则规则为:父 behavior 覆盖 子 behavior 中的同名属性或方法
生命周期:生命周期函数不会相互覆盖,而是在对应触发时机被逐个调用
对于不同的生命周期函数之间,遵循组件生命周期函数的执行顺序
对于同种生命周期函数:behavior 优先于组件执行,子 behavior 优先于 父 behavior 执行,靠前的 behavior 优先于 靠后的 behavior 执行
如果同一个 behavior 被一个组件多次引用,它定义的生命周期函数只会被执行一次
优先级规则参考:同名字段的覆盖和组合规则
二、使用 npm 包 小程序支持使用 npm 第三方安装包,来提升小程序的开发效率,但是小程序中使用 npm 有一些限制:
不支持依赖于 node.js 内置库的包(fs、path)
不支持依赖于浏览器内置对象的包(JQ)
不支持依赖于 C++ 插件的包
1、Vant Weapp
这是一套开源的小程序组件 ui 库,使用的是 MIT 开源协议,对于商业使用比较友好;官网地址:https://vant-contrib.gitee.io/vant-weapp/#/home
可参考官网的快速上手
1、npm 安装 Vant Weapp
打开终端 - npm安装:npm i @vant/weapp -S --production
这里需要看看有没有 package.json 文件,没有的话需要先执行指令 npm init -y 来初始化一个;
2、构建 npm(没有安装依赖都需要重新构建)
打开微信开发者工具,点击 工具 -> 构建 npm,并勾选 使用 npm 模块 选项,构建完成后,即可引入组件;
小程序无法时候 node_module 这个文件里面的内容,所以需要构建成一个 miniprogram_npm 文件,并且每次构建都需要删除这个miniprogram_npm 文件;
3、修改 app.js
将 app.json 中的 “style”: “v2” 去除,小程序的新版基础组件强行加上了许多样式,难以覆盖,不关闭将造成部分组件样式混乱;
4、使用 Vant
安装完成之后在 app.json 文件中的 usingComponents 节点中引入需要的组件,然后就可以全局使用了;
2、css变量定制样式
1、在根节点的内部定义一个 css 变量,然后在使用的时候借助 var 来引用;
> html{ --theme:"red" } .box{ background:var(--theme) }

需要注意的是,定义的变量必须 “–” 开头,它也是有作用域范围的,定义在那个区域下,就只能在这个区域里引用才会生效;
2、css 变量定制Vant 主题
在 app.wxss 文件中,写入变量名,变量名可参考:定制主题;只需要自定义的变量名跟这里需要修改的变量名一致,就可以直接改变原有的样式;
//app.wxss page{ --button-border-radius:10px; }

三、小程序 API 的 Promise 化 1、为什么要 Pronise 化
小程序中官方提供的异步 API 都是基于回调函数实现的,这样很容易导致回调地狱,代码的可读性、维护性都很低;
2、实现 Promise 化
1、主要依赖 miniprogram-api-promise 这个第三方 npm 包
npm i --save miniprogram-api-promise@1.0.4

2、在入口文件(app.js)需要调用一次 promisifyAll() 方法
//app.js import {promisifyAll} from 'miniprogram-api-promise'; const wxp = wx.p = {}; promisifyAll(wx,wxp);

这里 wxp 存放的就是 Promise 化之后的小程序 API,在使用的时候就可以直接使用 wx.p 来调用 Promise 化的 API 了;
3、调用 Promise 化的 API
async getInfo(){ const {data:res} = await wx.p.request({ url:"https://www.escook.cn/api/get", method:"GET", data:{ name:"sz", age:20 } }) console.log(res) }

四、全局数据共享(mobx-miniprogram、mobx-miniprogram-bindings ) 1、什么是全局数据共享
也可叫状态管理,解决小程序组件之间数据共享问题;常见的数据共享有:Vuex、Redux、Mobx
1、小程序中可以使用 mobx-miniprogram 配合 mobx-miniprogram-bindings 实现全局数据共享
mobx-miniprogram:用来创建 Store 实例对象
mobx-miniprogram-bindings:把 Store 实例对象里面的数据、方法绑定到组件或页面中使用
2、安装 mobx 相关包
npm i --save mobx-miniprogram@4.13.2 mobx-miniprogram-bindings@1.2.1

安装完成之后重新构建 npm;
2、创建 Store 实例对象
根目录创建文件夹 store,在文件夹里创建一个 store.js 文件;
//专门创建store实例对象 import { observable, action } from "mobx-miniProgram" export const store = observable({ userName:'xxs', age:20, //计算属性 get sum(){ return age++; }, //action 修改store 数据 updateAge:action(function(val){ this.age = 18; }) })

1、get 定义计算属性:只需要定义一个方法,然后以 get 开头,表明这个计算属性是只读的;
2、action 方法来修改 store 里面数据:外部想修改 store 只能通过调用 action 方法来修改;val 为外部传的参数;
3、在页面中使用 Store(createStoreBindings )
引入 store 和 createStoreBindings ,在 onLoad 自定义一个对象 storeBindings 调用 createStoreBindings 方法将 store、fields(字段、计算属性)、actions(方法)绑定到 this (当前页面) 上;在 onUnload 里面调用自定义对象 storeBindings 提供的销毁方法 destoryStoreBindings;
{{name}}:{{age}} +1

在页面中可以直接通过花括号 {{}} 使用绑定后的 store 字段;
import { createStoreBindings } from 'mobx-miniprogram-bindings'; import { store } from "../../store/store"; Page({ data: {}, /** * 生命周期函数--监听页面加载 */ onLoad: function (options) { this.storeBindings = createStoreBindings(this,{ store, //指定绑定的数据源 fields:['age','name'],//字段、计算属性 actions:['updateAge'] // 方法 }) }, /** * 生命周期函数--监听页面卸载 */ onUnload: function () { this.storeBindings.destoryStoreBindings(); }, //点击事件 btn1(e){ this.updateAge(); }, })

4、在组件中使用(storeBindingsBehavior)
引入 store 和 storeBindingsBehavior,提供behaviors 数组将进入的 storeBindingsBehavior 绑定;
{{name}}:{{age}} +1

import { storeBindingsBehavior } from 'mobx-miniprogram-bindings' import { store } from '../../store/store' Component({ behaviors:[storeBindingsBehavior],//通过storeBindingsBehavior实现自动绑定 storeBindings:{ store,//指定数据源 fields:{//绑定的字段、计算属性 name:"name",//前面的name是自定义字段,可以自己随意修改 age:(store)=>store.age,//也可以 ()=>store.age sum:'sum' }, actions:{ updateAge:"updateAge" } }, /** * 组件的方法列表 */ methods: { btn(){ this.updateAge() } } })

五、分包(subpackages ) 把完整的小程序项目按需求划分为不同的模块,在构建中打包成不同的子包,用户在使用时可以按需加载;这样的好处是:
优化小程序首次启动的下载时间
多团队共同开发时更好的进行解耦
1、分包后规则
1、项目构造
主包:包含项目的启动页或者 TabBar 页面,以及一些公共资源
分包:当前分包相关的页面和资源
2、加载规则
小程序启动时默认会下载主包和启动主包内页面(tabBar),在进入某个分包页面时才会下载对应的分包,下载完之后展示;
3、大小限制
整个小程序的主包+所有分包大小不能超过 16 M,主包或单个分包大小不能超过 2 M;如果超过则小程序发包会失败!
2、分包基本用法
在 app.json 文件中通过 subpackages 来声明分包,声明之后会自动创建相应的文件:
//pages平级 "subpackages":[ { "root": "package1", "name": "p1", "pages":[ "pages/dog/dog", "pages/cat/cat" ] } ]

root 声明这个分包的名称,name 是分包的别名,pages 是分包里面的页面;生成文件如下:
前端|微信小程序 - 进阶(自定义组件、promis化、mobx、分包、自定义tabBar)
文章图片

每个包的大小我们可以在微信开发工具-详情-基本信息里面查看;
3、打包原则
1、小程序会按 subpackages 的配置进行分包, subpackages 以外的目录将会打包到主包中;
2、主包也有自己的 pages ,也就是最外层的 pages;
3、tabBar 页面必须在主包里面;
4、分包之间不能相互嵌套;
4、引用原则
1、主包内资源可以被分包引用;
2、分包内的资源只能当前分包引用,其他分包和主包无法引用;
5、独立分包(independent)
本质上也是分包,但是它比较特殊,可以独立于主包和其他分包而单独运行;
默认情况下,用户打开小程序只能从主包进入,然后再去访问分包;独立分包则是用户可以跳过主包,直接进入分包中;一个小程序可以有多个独立分包;
1、定义独立分包
其实跟简单,独立分包跟普通分包在配置上基本一样,唯一区别是在 app.json 配置独立分包的时候需要在这个包里面添加一个配置:independent:true;
"subpackages":[ { "root": "package1", "pages":[ "pages/dog/dog", "pages/cat/cat" ], "independent": true } ]

注意:独立分包里面不能引用主包里面的资源;
6、分包预下载(preloadRule)
在进入主页面的时候会触发分包进行预下载行为,这样是为了提升分包的启动速度;在 app.json 里面,使用 preLoadRule 节点定义分包的预下载规则;
"preloadRule": { "pages/home/home": { "network": "all", "packages": ["package1"] } },

pages/home/home 是主页面路径,network 是指定预下载网络模式:all、wifi,packages 是配置需要预下载的分包的,可以是分包的 root 或者 name;
注意:同一个分包(主包)中的页面享有共同的预下载大小限额 2M,限额会在工具中打包时校验
六、自定义 tabBar 可参考:https://developers.weixin.qq.com/miniprogram/dev/framework/ability/custom-tabbar.html
1、配置
1、在 app.json 中的 tabBar 项指定 custom 字段,同时其余 tabBar 相关配置(list)也补充完整,保证低版本的兼容;
2、添加 tabBar 代码文件,根目录创建固定文件夹 custom-tab-bar ,这个文件夹小程序会自动访问,然后在文件夹下创建一个 index 组件;
3、借助 Vant weapp 来自定义导航组件;
【前端|微信小程序 - 进阶(自定义组件、promis化、mobx、分包、自定义tabBar)】如果没有使用组件库,可以参考小程序官网自定义 tabBar 最后面的一个链接,可以直接打开一个小程序项目;

    推荐阅读