微信小程序 - 进阶(自定义组件、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 文件中直接使用

<test></test>

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:用来接收外界传递到组件中的数据;

<test min="10"></test>
  //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
<view>
	<view>这是一个组件</view>
	//对于不确定的内容,使用 slot 占位,具体内容由组件的使用者决定
	<slot></slot>
</view>

//调用
<test>
	<view>这个内容会渲染到插槽位置</view>
</test>

2、启用多个插槽:小程序中如果想使用多个插槽,需要在组件中进行配置

Component({
  options: {
    multipleSlots: true // 组件使用多 slot
  }
})

多个插槽需要给 slot 定义一个 name 来区分

//组件 test
<view>
	<slot name="head"></slot>
	<view>这是一个组件</view>
	//对于不确定的内容,使用 slot 占位,具体内容由组件的使用者决定
	<slot name="foot"></slot>
</view>

//调用
<test>
	<view slot="head">这是头部的内容</view>
	<view slot="foot">这是底部的内容</view>
</test>

12、父子组件数据传递(properties 、triggerEvent())

1、属性绑定
父组件向子组件的指定属性设置数据,仅能设置 JSON 兼容的数据,无法传递方法;

子组件在 properties 节点上声明对应的属性并使用:

//子组件
properties: {
    min:{
      type:Number,
      value:0
    }
}
//父组件
<test min="2"></test>

子组件可以对 properties 的属性值进行修改,但是不会直接传递给父组件,如果想传递给父组件就需要用到下面的方法:

2、事件绑定
子组件向父组件传递数据,可以传递任何数据;

父组件 js 文件中定义事件,并在 wxml 文件中绑定事件,子组件调用 this.triggerEvent(事件名,参数) 函数将数据发送给父组件,然后父组件中通过 e.detail 获取到数据:

//父组件 js,定义一个方法接收子组件通过info事件传递的值
getChildInfo(e){
  console.log(e.detail);
}
//父组件 wxml,定义一个方法 info 给子组件使用
<test bind:info="getChildInfo"></test>
//还可以这样绑定,不过推荐使用上面那种
<test bindinfo="getChildInfo"></test>

//子组件传值,在btn 点击事件中传值整个 data
 btn(){
   this.triggerEvent("info",this.data)
 }

这个流程跟 vue 的子组件传值给父组件其实是差不多的;

3、获取组件实例
父组件可以通过 this.selectComponent() 方法获取子组件的实例,这也可以访问子组件的任何数据和方法;this.selectComponent() 方法接收一个选择器(id、class),不可以使用其他选择器;

//wxml
<test class="test"></test>
//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 来引用;

<style>
html{
	--theme:"red"
}
.box{
	background:var(--theme)
}
</style>

需要注意的是,定义的变量必须 “–” 开头,它也是有作用域范围的,定义在那个区域下,就只能在这个区域里引用才会生效;

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;

<view>{{name}}:{{age}}</view>
<van-button bindtap="btn1" class="my-button">+1</van-button>

在页面中可以直接通过花括号 {{}} 使用绑定后的 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 绑定;

<view>{{name}}:{{age}}</view>
<van-button bindtap="btn1" class="my-button">+1</van-button>
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)_第1张图片
每个包的大小我们可以在微信开发工具-详情-基本信息里面查看;

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 来自定义导航组件;

如果没有使用组件库,可以参考小程序官网自定义 tabBar 最后面的一个链接,可以直接打开一个小程序项目;

你可能感兴趣的:(前端,api,promis化,自定义组件,分包,自定义tabBar,mobx)