compoents->test
文件夹。components->test
文件夹上,鼠标右键,点击"新建Component
"组件的引用方式分为: "局部引用"和 “全局引用”,顾名思义:
在页面的.json配置文件中引用组件的方式,叫做"局部引用"。
home.wxss
引用组件的操作:
{
"usingComponents": {
"my-test1":"/components/test/test"
}
}
home.wxml
使用组件的操作
<text>首页text>
<my-test1>my-test1>
其他页面并不会展示这个组件的信息
我们只需在app.json的位置出,与window平级编写以下配置即可
"usingComponents": {
"my-test1":"/components/test/test"
},
从表面来看,组件和页面都是由. js 、.json、.wxml和.wxss着四个文件组成的。但是组件和页面的.js与.json文件明显不同。
component:true
"属性。Component()
函数不是Page()
。组件的js文件
// components/test/test.js
Component({
/**
* 组件的属性列表
*/
properties: {
},
/**
* 组件的初始数据
*/
data: {
},
/**
* 组件的方法列表
*/
methods: {
}
})
组件的.json
{
"component": true,
"usingComponents": {}
}
默认情况下,自定义组件的样式只对当前组件生效,不会影响组件之外的UI结构,如图所示:
id选择器、属性选择器、标签选择器不受样式隔离的影响
。建议: 在组件和引用组件的页面中建议使用class选择器,不要id、属性、标签选择器。
默认情况下,自定义组件的样式隔离性能够防止组件内外样式互相干扰的问题。但有时,我们需要在外界能够控制组件内部的样式,此时,可以通过stylesolation修改组件的样式隔离选项。
进行隔离->互不影响
1. 第一种:在组件的 .js文件中新增如下配置
Component({
// 隔离性
options:{
styleIsolation:'isolated'
},
}
2. 第二种:在组件的.json文件中新增如下配置
{
styleIsolation:'isolated'
}
styleIsolation
参数 描述
`互相隔离`
isolated 表示启用样式隔离,再定以组件内外,使用class指定的样式将不会相互影响。
`外面会影响到组件,组件不会影响到外部`
apply-shared 表示页面wxss样式将影响到自定义组件,但自定义组件wxss中指定的样式不会影响页面。
`组件会影响到外部,外部不会影响到组件`
shared 表示页面wxss样式将影响到自定义组件,自定义组件wxss中指定的样式也会影响页面和其他设置乐 apply-shared或shared的自定义组件。
在小程序组件中,用于组件模板渲染的私有数据,需要定义到data节点中:
组件.wxml
<text>components/test/test.wxmltext>
<view>
<text>{{count}}text>
view>
组件.js test.js
// components/test/test.js
Component({
// 隔离性
options:{
styleIsolation:'isolated'
},
/**
* 组件的属性列表
*/
properties: {
},
/**
* 组件的初始数据
*/
data: {
count:0
},
/**
* 组件的方法列表
*/
methods: {
}
})
在小程序组件中,事件处理函数和自定义方法需要定义到methods节点中:
自定义的方法:我们要养成一个规范:以下划线开头。事件处理函数我们不以下划线开头!!!
test.js
// components/test/test.js
Component({
// 隔离性
options:{
styleIsolation:'isolated'
},
/**
* 组件的属性列表
*/
properties: {
},
/**
* 组件的初始数据
*/
data: {
count:0
},
/**
* 组件的方法列表
*/
methods: {
// 1. 自增事件处理函数...
addCount(){
this.setData({
count:this.data.count+1
})
this._showCount();
},
_showCount(){ // 2. 提示框的操作
wx.showToast({
title: '点击按钮:'+ this.data.count,
})
}
}
})
test.wxml
<text>components/test/test.wxmltext>
<view>
<text>{{count}}text>
view>
<button type="primary" bindtap="addCount">按我+1button>
在小程序组件中,properties是组件的对外属性,用来接受外界传递到组件的数据
,实列实列代码如下
properties: {
// 1. 第一种方式: 简化的方式->无法指定默认值
// max:Number,
// 2. 第二种方式: 完整的定义方式 [当需要指定属性默认值时,建议使用此方式]
max:{
type:Number, // 属性值的数据类型
value:10 // 属性默认值
}
},
组件 test.js
// components/test/test.js
Component({
// 隔离性
options:{
styleIsolation:'isolated'
},
/**
* 组件的属性列表
*/
properties: {
// 1. 第一种方式: 简化的方式->无法指定默认值
// max:Number,
// 2. 第二种方式: 完整的定义方式 [当需要指定属性默认值时,建议使用此方式]
max:{
type:Number, // 属性值的数据类型
value:10 // 属性默认值
}
},
/**
* 组件的初始数据
*/
data: {
count:0
},
/**
* 组件的方法列表
*/
methods: {
// 1. 自增事件处理函数...
addCount(){
if(this.data.count>=this.properties.max) return
this.setData({
count:this.data.count+1
})
this._showCount();
},
_showCount(){ // 2. 提示框的操作
wx.showToast({
title: '点击按钮:'+ this.data.count,
})
}
}
})
父home.wxml
<text class="t1">首页text>
<my-test1 max="4">my-test1>
在小程序的组件中,properties属性和data数据的用法相同、它们都是可读可写的,只不过:
由于data数据和properties属性在本质上没有任何区别,因此properties属性的值也可以用于页面的渲染,或使用setData为properties中的属性重新赋值。
// components/test/test.js
Component({
// 隔离性
options:{
styleIsolation:'isolated'
},
/**
* 组件的属性列表
*/
properties: {
// 1. 第一种方式: 简化的方式->无法指定默认值
// max:Number,
// 2. 第二种方式: 完整的定义方式 [当需要指定属性默认值时,建议使用此方式]
max:{
type:Number, // 属性值的数据类型
value:10 // 属性默认值
}
},
/**
* 组件的初始数据
*/
data: {
count:0
},
/**
* 组件的方法列表
*/
methods: {
// 1. 自增事件处理函数...
addCount(){
this.setData({
count:this.data.count+1,
max:this.properties.max+1
})
this._showCount();
},
_showCount(){ // 2. 提示框的操作
wx.showToast({
title: '点击按钮:'+ this.data.count,
})
}
}
})
数据监听器用途用于监听和响应任何数据字段的变化,从而执行特定的操作。它的作用类似于Vue中的watch侦听器
。在小程序组件中。
1. 在components新建一个文件夹
2. 在这个新建的文件夹中引入compoents
3. 在app.json文件中配置注册 新建的这个组件
4. 在app.wxml文件中使用我们新建的这个组件
test2.js
初始化数据并设置监听的方法
/**
* 组件的监听器-> 假如说监听的数据发生了变化,那么就会触发这个事件
*/
observers:{
'n1,n2':function(newN1,newN2){ // 左边是监听的数据,右侧是方法(监听到的新值)
this.setData({
sum:newN2+newN1
})
}
}
// components/test2/test2.js
Component({
/**
* 组件的初始数据
*/
data: {
n1:0,
n2:0,
sum:0
},
/**
* 组件的方法列表
*/
methods: {
addN1(){
this.setData({
n1:this.data.n1+1
})
},
addN2(){
this.setData({
n2:this.data.n2+1
})
}
},
/**
* 组件的监听器-> 假如说监听的数据发生了变化,那么就会触发这个事件
*/
observers:{
'n1,n2':function(newN1,newN2){ // 左边是监听的数据,右侧是方法(监听到的新值)
this.setData({
sum:newN2+newN1
})
}
}
})
test2.wxml
<view>
{{n1}}+{{n2}}={{sum}}
view>
<button bindtap="addN1">n1+1button>
<button bindtap="addN2">n2+1button>
数据监听器支持监听对象中单个或多个属性的变化。
Component({
obervers:{
'对象.属性1,对象.属性2':function(新属性A的值,新属性B的值){
// 事件触发的三种情况
1. 属性A的值发生了变化
2. 属性B的值发生了变化
3. 直接为整个对象发生了变化
}
}
})
注意点: 假如我们data区域的是对象。我们想要给对象里的某一个属性赋值:我们需要用单引号括起来
this.setData({
'对象.属性名1':
})
test3.js
// components/test3/test3.js
Component({
/**
* 组件的属性列表
*/
properties: {
},
/**
* 组件的初始数据
*/
data: {
rgb:{
r:0,
g:0,
b:0
},
fullColor:'0,0,0'
},
observers:{
'rgb.r,rgb.g,rgb.b':function(newR,newG,newB){
this.setData({
fullColor:newR+','+newG+','+newB
})
}
},
/**
* 组件的方法列表
*/
methods: {
changeR(){
if(this.data.rgb.r>255) return
this.setData({
'rgb.r':this.data.rgb.r+10
})
},
changeG(){
if(this.data.rgb.g>255) return
this.setData({
'rgb.g':this.data.rgb.g+10
})
},
changeB(){
if(this.data.rgb.b>255) return
console.log()
this.setData({
'rgb.b':this.data.rgb.b+10
})
}
}
})
test3.wxml
<view style="background-color: rgb({{fullColor}}); width: 100%;height: 300rpx">
view>
<view>0
背景颜色的RGB值为: {{fullColor}}
view>
<view style="text-align: center;margin-top: 45rpx;">
<button type="default" size="mini" bindtap="changeR">Rbutton>
<button type="primary" size="mini" bindtap="changeG">Gbutton>
<button type="warn" size="mini" bindtap="changeB">Bbutton>
view>
如果某个对象中需要被监听的属性太多,为了方便,可以使用通配符 ** 来监听对象中的所有属性的变化:
我们在使用欸都时候,需要用到通配符和反引号
observers:{
'rgb.**':function(obj){
this.setData({
fullColor:`${obj.r},${obj.g},${obj.b}`
})
}
},
概念: 纯数据字段指的是那些不用于界面渲染的data字段。
应用场景: 列如有些情况下,某些data中的字段既不会展示在界面上,也不会传递给其他组件。仅仅在当前组件内部使用。带有这种特性的data字段适合设置为纯数据字段。
在Component构造器的options节点中,指定 pureDataPattern为一个正则表达式,字段名符合这个正则表达式的字段将成为纯数据字段。
生命周期函数 | 参数 | 描述说明 |
---|---|---|
created |
无 | 在组建刚刚被创建的时候执行 |
attached |
无 | 在组件实列进入页面节点树时执行 |
ready | 无 | 在组件在视图层布局完成后执行 |
moved | 无 | 在组建实列被移动到节点树另一个位置时执行 |
detached |
无 | 在组件实列被从页面节点数移除时执行 |
error | 无 | 每当组件方法抛出错误时执行 |
在小程序组件中,最重要的生命周期函数有3个,分别是" created、attached、detached。"
刚被创建好的时候
,created生命周期函数会被触发组件完全初始化完毕、进入页面节点树后
,attached生命周期函数才会触发在小程序组件中,生命周期函数可以直接定义在Component构造器的第一季参数中,可以在lifetimes字段内进行声明(这是推荐的方式,其优先级最高)
lifetimes:{
created(){
console.log("被创建了")
},
attached(){
console.log('所有的数据初始化完毕')
}
},
有时候,自定义组件的行为依赖于页面状态的变化,此时就需要用到组件所在页面的声明周期。
每当触发页面的show生命周期的函数时候,我们希望能够重新生成一个随机的RGB颜色值。
在自定义组件中,塑件所在页面的生命周期函数有如下3个:
生命周期函数 参数 描述
show 无 组件所在的页面被展示时执行
hide 无 组件所在的页面被隐藏时执行
resize object Size 组件所在的页面尺寸发生变化时执行
// components/test3/test3.js
Component({
pageLifetimes:{// 页面在组件的生命周期
show(){
console.log('show')
},
hide(){
console.log('hide')
},
resize(){
console.log('resize')
}
},
lifetimes:{ // 组件的生命周期
created(){
console.log("被创建了")
},
attached(){
console.log('所有的数据初始化完毕')
}
}
})
lifetimes:{ // 组件的生命周期
created(){
console.log("被创建了")
},
attached(){
console.log('所有的数据初始化完毕')
this.setData({
fullColor:Math.random()*256+','+Math.random()*256+','+Math.random()*256
})
console.log(this.data.fullColor)
}
},
再打自定义组件的wxml结构中,可以提供一个< slot>节点(插槽),用于承载组件使用者提供的wxml结构。
在小程序中,默认每个自定义组件中只允许使用一个 < slot>进行占位,这种个数上的限制叫做单个插槽。
test4.js
<view>
<view>
这里是组件的内部结构
view>
<slot>slot>
view>
home.wxml
<text class="t1">首页text>
<my-test4>
<view>
这是通过插槽填充的数据
view>
my-test4>
在小程序的自定义组件中,需要使用多 < slot> 插槽时,可以在组件的.js文件中。通过以下的方式进行启用,默认的是一个插槽:
test4.js
// components/test4/test4.js
Component({
options:{
multipleSlots:true
}
})
test4.wxml
用name取别名
<view>
<slot name="before">slot>
<view>
这里是组件的内部结构
view>
<slot name="after">slot>
view>
home.wxml
通过slot属性进行绑定
<text class="t1">首页text>
<my-test4>
<view slot="before">
这是通过插槽填充的数据
view>
my-test4>
属性绑定
用于实现父向子传值
,而且只能传递普通类型的数据
,无法将方法传递给子组件。
// 父组件的 data 节点
data:{
count:0
}
// 父组件的wxml结构 count="{{count}}"
<my-test3 count="{{count}}"></my-test3>
<view>{{count}}</view>
我们子组件在properties节点种声明对应的属性并使用
// 子组件的 properties 节点
properties:{
count:Number
}
// 子组件的wxml结构
<text>子组件->{{count}}</text>
- 父亲传递函数
home.wxml
<text class="t1">首页text>
<view>
父组件中Count的值为: {{count}}
view>
<view>
---------------
view>
// 传递函数
<my-test5 count="{{count}}">my-test5>
- 儿子组件接受参数
tes5t.js
// components/test5/test5.js
Component({
/**
* 组件的属性列表
*/
properties: {
// 注册-> 第一个是注册的变量名,第二个是注册的变量类型
count: Number
},
/**
* 组件的初始数据
*/
data: {
},
/**
* 组件的方法列表
*/
methods: {
}
})
- 儿子组件输出传递过来的组件
test5.wxml
<text>父组件传递过来的数据为 : {{count}}text>
- 儿子调用自增的函数
test5.wxml
<text>父组件传递过来的数据为 : {{count}}text>
<button type="primary" bindtap="addCount">点我+1button>
test5.js
// components/test5/test5.js
Component({
/**
* 组件的属性列表
*/
properties: {
// 注册-> 第一个是注册的变量名,第二个是注册的变量类型
count: Number
},
/**
* 组件的初始数据
*/
data: {
},
/**
* 组件的方法列表
*/
methods: {
addCount(){
console.log(this)
this.setData({
count:this.properties.count+1
})
}
}
})
事件绑定用于实现子向父传值,可以传递任何类型的数据。
1.在父组件的js中,定义一个函数,这个函数即将通过自定义事件的形式,传递给子组件
2.在父组件的wxml中,通过自定义事件的形式,将步骤1中定义的函数引用,传递给子组件
3.在子组件的js中,通过调用this.triggerEvent('自定义事件名',{/* 参数对象*/}),将数据传递给父组件
4.在父组件的js中,通过e.detail获取到子组件传递过来的数据
- 父组件定义一个函数
home.js
Page({
syncCount(){
console.log('syncCount')
},
/**
* 页面的初始数据
*/
data: {
count:0
},
})
- 父组件将定义的方法传递给子组件
home.wxml
<text class="t1">首页text>
<view>
父组件中Count的值为: {{count}}
view>
<view>
---------------
view>
<my-test5 count="{{count}}" bind:syc1="syncCount">my-test5>
- 子组件绑定触发事件
test5.js
// components/test5/test5.js
Component({
/**
* 组件的属性列表
*/
properties: {
// 注册-> 第一个是注册的变量名,第二个是注册的变量类型
count: Number
},
/**
* 组件的初始数据
*/
data: {
},
/**
* 组件的方法列表
*/
methods: {
addCount(){
this.setData({
count:this.properties.count+1
})
// 触发自定义事件,将数值同步给父组件.。 第一个参数是: 自定义事件名,第二个参数是: 传给父类的数据{value:''}
this.triggerEvent('syc1',{value:this.properties.count})
}
}
})
- 父组件进行同步接受数据
test5.js
Page({
syncCount(e){
console.log('syncCount',e)
this.setData({
count:e.detail.value
})
},
/**
* 页面的初始数据
*/
data: {
count:0
}
})
可在父组件里调用 this.selectComponent(“id或class选择器”),获取子组件的实列对象,从而直接访问子组件的任意数据和方法。调用时需要传入一个选择器。
home.wxml
<text class="t1">首页text>
<view>
父组件中Count的值为: {{count}}
view>
<view>
---------------
view>
<my-test5 count="{{count}}" bind:syc1="syncCount" class="customerA">my-test5>
<button type="warn" bindtap="getChild">获取子组件的实列对象button>
home.js
Page({
getChild(){
// 这里我们通过类选择器获取实列,并用e接受
const e=this.selectComponent('.customerA')
console.log('子组件的实列->',e)
// 我们改变这个count值。注意这里我们不能用this,因为this是父组件并不是子组件。所以我们要用子组件的实列对象进行操作。
e.setData({
count:e.data.count+10
})
},
syncCount(e){
console.log('syncCount',e)
this.setData({
count:e.detail.value
})
},
/**
* 页面的初始数据
*/
data: {
count:0
}
})
behaviors是小程序中,用于实现组件间代码共享的特性,类似于Vue.js中的 “mixins”
每个 behavioor 可以包含一组属性、数据、生命周期函数和方法。组件引用它时,它的属性、数据和方法会被合并到组件中
。
每个组件可以引用多个behavior
,behavior也可以引用其他的 behavior。
调用 Behavior方法即可创建一个共享的 behavior 实列对象,供所有的组件使用:
我们在根目录下创建Behavior这个文件夹中创建一个文件 behavior.js
my-behaviors.js
// 1. 创建一个Behavior并共享出里面的数据
module.exports= Behavior({
data:{
username:'jsxs'
},
properties:{},
methods:{}
})
在组件中,使用 require()
方法导入需要的behavior,挂载后 即可访问 behavior中的数据或方法
。
test5.js
// 1.在我们要用的组件的 .js上面的文件中引入我们自定义的共享数据
const myBehavior=require('../../behaviors/my-behavior')
// 2. 进行数据的挂载
behaviors:[myBehavior],
// components/test5/test5.js
// 1.在我们要用的组件的 .js上面的文件中引入我们自定义的共享数据
const myBehavior=require('../../behaviors/my-behavior')
Component({
// 2. 进行数据的挂载
behaviors:[myBehavior],
/**
* 组件的属性列表
*/
properties: {
// 注册-> 第一个是注册的变量名,第二个是注册的变量类型
count: Number
},
/**
* 组件的初始数据
*/
data: {
},
/**
* 组件的方法列表
*/
methods: {
addCount(){
this.setData({
count:this.properties.count+1
})
// 触发自定义事件,将数值同步给父组件.。 第一个参数是: 自定义事件名,第二个参数是: 传给父类的数据{value:''}
this.triggerEvent('syc1',{value:this.properties.count})
}
}
})
test5.wxml
我们继续通过Mustach语法进行获取数据
<text>父组件传递过来的数据为 : {{count}}text>
<view>
通过behavior获取的数据: {{username}}
view>
<button type="primary" bindtap="addCount">点我+1button>
目前,小程序已经支持使用 npm 安装第三方包,从而来提高小程序的开发效率,但是,在小程序中使用npm包有3个限制:
Node.js
内置库的包浏览器内置对象
的包C++
插件的包总结: 虽然npm上的包有千千万,但是能够供小程序使用的包却:“为数不多”。
Vant Weapp是有赞助前端团队开源的小程序UI组件库,助理于开发者快速搭建小程序应用。它所使用的是 MIT开源许可协议,对商业使用比较友好。
官方文档地址: https://vant-contrib.gitee.io/vant-weapp/#/home
在小程序项目中,安装Vant组件库主要分为如下3步:
初始化项目
npm init -y
- 通过 npm 安装 (建议指定版本为 @1.3.3)
npm i @vant/[email protected] -S --production
- 构建npm包
- 修改app.json
安装完 Vant 组件库之后,可以在app.json
的usingComponents
节点中引入需要的组件,即可在wxml中直接使用组件。
- 在app.json这个文件中写
home.json
"usingComponents": {
"van-button": "@vant/weapp/button/index"
},
home.wxml
<text class="t1">首页text>
<van-button type="default">默认按钮van-button>
<van-button type="primary">主要按钮van-button>
<van-button type="info">信息按钮van-button>
<van-button type="warning">警告按钮van-button>
<van-button type="danger">危险按钮van-button>
- 介绍全局主题样式
Vant Weapp 使用CSS变量来实现定制主题。关于CSS变量的基本用法: 请参考MDN文档。
https://developer.mozilla.org/zh-CN/docs/Web/CSS/Using_CSS_custom_properties
自定义属性(有时也被称作CSS变量或者级联变量)是由CSS作者定义的,它包含的值可以在整个文档中重复使用。由自定义属性标记设定值(比如: --main-color: black;
),由 var() 函数来获取值(比如: color: var(–main-color);
)
复杂的网站都会有大量的CSS代码,通常也会有许多重复的值。
举例:同样一个颜色值可能在成千上百个地方被使用到,如果这个值发生了变化,需要全局搜索并且一个一个替换
。自定义属性在某个地方存储一个值,然后在其他许多地方引用它。另一个好处是语义化的标识。如:–main-text-color
会比 #00ff00 更易理解,尤其是这个颜色值在其他上下文中也被使用到。自定义属性受级联的约束,并从其父级继承其值。
--main-bg-color: brown;
background-color: var(--main-bg-color);
- 定制全局主题样式
在app.wxss中,写入CSS变量,即可对全局生效:
1. 为什么要用page做节点?
2. 为什么名字是这些?
app.json
/**app.wxss**/
.container {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
padding: 200rpx 0;
box-sizing: border-box;
}
/* 我们在这里为什么要使用page节点. */
page{
/* 为什么我们的按钮名字是这些? https://github.com/youzan/vant-weapp/blob/dev/packages/common/style/var.less */
--button-danger-background-color: #C00000;
--button-danger-border-color: #D60000;
}
home.wxml
<text class="t1">首页text>
<van-button type="default">默认按钮van-button>
<van-button type="primary">主要按钮van-button>
<van-button type="info">信息按钮van-button>
<van-button type="warning">警告按钮van-button>
<van-button type="danger">危险按钮van-button>
默认情况下,小程序官方提供的异步API 都是基于回调函数实现的,列如: 网络请求的API需要按照如下的方式调用:
wx.request({
method: '',
url:'',
data:{},
success:()=>{}, // 请求成功的回调函数
fail:()=>{}, // 请求失败的回调函数
complete:()=>{} // 请求完成的回调函数
})
缺点: 容易造成回调地狱的问题,代码的可读性、维护性差!
API Promise化
,指的是提供额外的配置
,将官方提供的、基于回调函数的异步API,升级改造为基于Pormise的异步API
,从而提高代码的可读性、维护性,维护性,避免回调地狱的问题。
在小程序中,实现API Promise化主要依赖于 miniprogram-api-promise
这个第三方的npm包。
npm i --save [email protected]
记住: 我们每次在微信小程序安装一个包,我们不能够立马进行使用,我们需要重新构建npm。
第一步: 删除包
第二步 重新构建
第三步: 成功之后
- 第一步在 app.js中引入
app.js
在小程序入口文件中(app.js),只需调用一次promisifyAll()方法.即可实现异步 API 的promise化。
// app.js
import {promisifyAll} from 'miniprogram-api-promise'
const wxp=wx.p={}
promisifyAll(wx,wxp)
- 在home.wxml
hoem.xml
绑定方法
<text class="t1">首页text>
<van-button type="primary" bindtap="getinfo">默认按钮van-button>
- 在home.js
Page({
async getinfo(){
const res= await wx.p.request({
method:'GET',
url:'https://applet-base-api-t.itheima.net/api/get',
data:{
name:'zs',
age:20
}
})
console.log(res)
},
})
全局数据共享 (又叫做: 状态管理)是为了解决组件之间数据共享的问题。
开发中常用的全局数据共享方案有: Vuex、Redux、MobX等等。
在小程序中,可使用 mobx-miniporgram
配合 mobx-miniporgram-bindings
实现全局数据共享。
创建Store实列对象
。把Store中的共享数据或方法,绑定到组件或页面中使用
。在项目中运行如下的命令,安装MobX相关的包:
npm install --save [email protected] [email protected]
store/store.js
// 在这个js文件中,专门来常见Store的实列对象
import { action, observable } from "mobx-miniprogram"; // 引入MobX,这里的数据都不能自定义
// 抛出 Mobx
export const store = observable({
// 共享下面的变量
// (1).共享数据字段
numA:1,
numB:2,
// (2).计算属性 -》 关键字 get 表示这个计算属性是只能 读取的。
get sum(){
return this.numA+this.numB
},
// (3).actions 方法 用来修改store中的数据
updateNum1:action(function(step){ // 第一个是 自定义方法名, 第二个是 action
this.numA+=step
}),
updateNum2:action(function(step){
this.numB+=step
})
})
home.wxml
// 1. 导入包和实列对象
import { createStoreBindings } from 'mobx-miniprogram-bindings';
import { store } from '../../store/store';
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
// 绑定
this.storeBindings= createStoreBindings(this,{
store, // 1.实列对象
fields:['numA','numB','sum'], // 2. 我们在store.js中定义的属性
actions:['updateNum1','updateNum2'] // 3. 我们在store.js中定义的方法
})
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
// 解除绑定
this.storeBindings.destoryStoreBindings()
},
})
home.wxml
<text class="t1">首页text>
<view>
{{numA}}+{{numB}}={{sum}}
view>
<van-button type="primary" bindtap="btnHandler" data-step="{{1}}">numA+1van-button>
<van-button type="danger" bindtap="btnHandler" data-step="{{-1}}" >numA-1van-button>
home.js
import { createStoreBindings } from 'mobx-miniprogram-bindings';
import { store } from '../../store/store';
btnHandler(e){
console.log(e)
this.updateNum1(e.currentTarget.dataset.step)
},
// 1. 导入包和实列对象
import { createStoreBindings } from 'mobx-miniprogram-bindings';
import { store } from '../../store/store';
Page({
/**
* 页面的初始数据
*/
data: {
count:0
},
btnHandler(e){
console.log(e)
this.updateNum1(e.currentTarget.dataset.step)
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
// 绑定
this.storeBindings= createStoreBindings(this,{
store, // 1.实列对象
fields:['numA','numB','sum'], // 2. 我们在store.js中定义的属性
actions:['updateNum1','updateNum2'] // 3. 我们在store.js中定义的方法
})
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
this.storeBindings.destoryStoreBindings()
},
})
我们在组件的 .js页面进行引入。
test.js
// components/test/test.js
// 第一步: 映射到本组件中
import { storeBindingsBehavior } from 'mobx-miniprogram-bindings';
// 第二步: 接受映射
import { store } from '../../store/store';
Component({
// 第三步: 通过storeBindingsBehavior来实现自动绑定
behaviors:[storeBindingsBehavior],
storeBindings:{
// 第四步: 指定要绑定的数据源Store
store,
// 第五步: 指定要绑定的字段数据
fields:{
// 格式为: numA->'绑定的数据源名'
numA:'numA', //绑定字段的第一种方式
numB:'numB', // 绑定字段的第二种方式
sum:'sum' // 绑定字段的第三种方式
},
// 第六步: 指定绑定的方法
actions:{
updateNum2:'updateNum2'
}
},
})
test.wwxml
<view>
{{numA}}+{{numB}}={{sum}}
view>
<van-button type="primary" bindtap="btnHandler2" data-step="{{1}}">numB+1van-button>
<van-button type="primary" bindtap="btnHandler2" data-step="{{-1}}">numB-1van-button>
组件的.js
methods: {
btnHandler2(e){
this.updateNum2(e.target.dataset.step)
}
}
分包指的是把一个完整的小程序项目
,按照需求划分为不同的子包
,在构建时打包成不同的分包,用户在使用时按需进行加载
。
对小程序进行分包的好处主要有以下两点:
优化小程序首次启动的下载时间
。多团队共同开发
时可以更好的解耦协作
。分包前,小程序项目中所有的页面
和资源
都被打包到了一起,导致整个项目体积过大
,影响小程序首次启动的下载时间
。
分包后,小程序项目由 1个主包 + 多个分包
组成:
下载主包
并启动主包内页面
客户端会把对应分包下载下来
,下载完成后再进行展示目前,小程序分包的大小有以下两个限制:
- 如何创建分包
app.json
1. 新增一个属性对象 subPackages -> 内嵌有几个对象就是几个分包
2. 必须要写的一个 root属性 -> 用来指向分包的根目录名
3. pages: 用来指向我们生成的文件 -> 有多少个文件,就在这个分包下有多少页面
"subPackages": [
{
"root": "pkgA",
"pages": [
"pages/cat/cat",
"pages/dog/dog"
]
},
{
"root": "pkgB",
"pages": [
"pages/apple/apple"
]
}
],
{
"usingComponents": {
"van-button": "@vant/weapp/button/index",
"my-test1":"/components/test/test"
},
"pages":[
"pages/home/home",
"pages/message/message",
"pages/contact/contact",
"pages/info/info"
],
"subPackages": [
{
"root": "pkgA",
"pages": [
"pages/cat/cat"
]
}
],
"window":{
"backgroundTextStyle":"dark",
"navigationBarBackgroundColor": "#2b4b6b",
"navigationBarTitleText": "金橘社区",
"navigationBarTextStyle":"white",
"backgroundColor": "#efefef",
"onReachBottomDistance": 100
},
"tabBar": {
"list": [
{
"pagePath": "pages/home/home",
"text": "首页",
"iconPath": "images/index.png",
"selectedIconPath": "images/index-active.png"
},
{
"pagePath": "pages/message/message",
"text": "信息",
"iconPath": "images/mail.png",
"selectedIconPath": "images/mail-active.png"
},
{
"pagePath": "pages/contact/contact",
"text": "电话",
"iconPath": "images/phone.png",
"selectedIconPath": "images/phone-active.png"
}
]
},
"sitemapLocation": "sitemap.json"
}
- 分包的别名
"subPackages": [
{
"root": "pkgA",
"name": "p1",
"pages": [
"pages/cat/cat",
"pages/dog/dog"
]
},
{
"root": "pkgB",
"name": "p2",
"pages": [
"pages/apple/apple"
]
}
],
- 如何查看分包的各自体积
subpackages
的配置进行分包,subpackages 之外的目录将被打包到主包中无法引用
分包内的私有资源不能相互引用
私有资源可以引用
主包内的公共资源独立分包本质上也是分包
,只不过它比较特殊,可以独立于主包和其他分包而独立运行
。
最主要的区别: 是否依赖于主包才能运行
开发者可以按需,将某些具有一定功能独立性的页面
配置到独立分包
中。原因如下:
不依赖主包
即可运行,可以很大程度上提升分包页面的启动速度
注意: 一个程序种可以有多个独立分包
是否有indepentdent为 true 这个节点。如果有的话,就是独立分包
将分包okgB转变为 独立分包
{
"root": "pkgB",
"name": "p2",
"pages": [
"pages/apple/apple"
],
"independent": true
}
独立分包和普通分包以及主包之间,是相互隔绝
的,不能相互引用彼此的资源
!
主包无法引用独立分包
内的私有资源独立分包之间
,不能相互引用私有资源独立分包和普通分包之间
,不能相互引用私有资源独立分包中不能引用主包内的公共资源
。普通分包是可以实现引用主包内的资源。分包预下载指的是:在进入小程序的某个页面时,由框架自动预下载可能需要的分包
,从而提升进入后续分包页面时的启动速度。
比如 进入到 联系页面,可能要用到 cat 页面,我们就预下载 pack1 分包
预下载分包的行为,会在进入指定的页面时触发
。在 app.json 中,使用 preloadRule
节点定义分包的预下载规则
"preloadRule": {
"pages/contact/contact":{
"packages": ["pkgA"],
"network": "all"
}
},
同一个分包中的页面享有共同的预下载大小限额2M,例如:
共同的预下载不能超过 2兆
自定义tabBar分为3大步骤
app.json
中的 tabBar
项指定 custom
字段,同时其余 tabBar
相关配置也补充完整。tab
页的 json
里需声明 usingComponents
项,也可以在 app.json
全局开启。
- 为了保证低版本兼容以及区分哪些页面是 tab 页,tabBar 的相关配置项需完整声明,但这些字段不会作用于自定义 tabBar 的渲染。
"tabBar": {
"custom": true,
"list": [
{
"pagePath": "pages/home/home",
"text": "首页",
"iconPath": "images/index.png",
"selectedIconPath": "images/index-active.png"
},
{
"pagePath": "pages/message/message",
"text": "信息",
"iconPath": "images/mail.png",
"selectedIconPath": "images/mail-active.png"
},
{
"pagePath": "pages/contact/contact",
"text": "电话",
"iconPath": "images/phone.png",
"selectedIconPath": "images/phone-active.png"
}
]
},
- 添加 tabBar 代码文件
在代码根目录下添加入口文件:
custom-tab-bar/index.js
custom-tab-bar/index.json
custom-tab-bar/index.wxml
custom-tab-bar/index.wxss
- 引入Vant做效果装饰
app.json
引用的是单个组件
"usingComponents": {
"van-tabbar": "@vant/weapp/tabbar/index",
"van-tabbar-item": "@vant/weapp/tabbar-item/index"
}
- 自定义选中图标和未选中图标
<van-tabbar-item info="3">
<image
slot="icon"
src="/images/index.png" 选中的路径图片
mode="aspectFit"
style="width: 30px; height: 18px;"
/>
<image
slot="icon-active"
src="/images/index-active.png" 未选中的路径图片
mode="aspectFit"
style="width: 30px; height: 18px;"
/>
首页
van-tabbar-item>
<van-tabbar active="{{ active }}" bind:change="onChange">
<van-tabbar-item info="3">
<image
slot="icon"
src="/images/index.png"
mode="aspectFit"
style="width: 30px; height: 18px;"
/>
<image
slot="icon-active"
src="/images/index-active.png"
mode="aspectFit"
style="width: 30px; height: 18px;"
/>
首页
van-tabbar-item>
<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>
- 循环遍历自定义图标
赋值app.json的tabBar的list数组到index.js的data区域中
对象其实也是 “” 引用的,只不过在data区域可以省略
"list": [
{
"pagePath": "pages/home/home",
"text": "首页",
"iconPath": "/images/index.png",
"selectedIconPath": "/images/index-active.png"
},
{
"pagePath": "pages/message/message",
"text": "信息",
"iconPath": "/images/mail.png",
"selectedIconPath": "/images/mail-active.png"
},
{
"pagePath": "pages/contact/contact",
"text": "电话",
"iconPath": "/images/phone.png",
"selectedIconPath": "/images/phone-active.png"
}
]
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>
index.wxml
我们只需要在Vant的组件上添加 一个 info="x" 即可
<van-tabbar active="{{ active }}" bind:change="onChange">
<van-tabbar-item wx:for="{{list}}" wx:key="index" info="2">
<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>
- 如何让徽标不超过tabBar的指定框
第一步:在index.js中添加属性
"options":{
styleIsolation:'shared'
},
// custom-tab-bar/index.js
Component({
"options":{
styleIsolation:'shared'
},
/**
* 组件的属性列表
*/
properties: {
},
/**
* 组件的初始数据
*/
data: {
active: 0,
list: [
{
"pagePath": "pages/home/home",
"text": "首页",
"iconPath": "/images/index.png",
"selectedIconPath": "/images/index-active.png"
},
{
"pagePath": "pages/message/message",
"text": "信息",
"iconPath": "/images/mail.png",
"selectedIconPath": "/images/mail-active.png"
},
{
"pagePath": "pages/contact/contact",
"text": "电话",
"iconPath": "/images/phone.png",
"selectedIconPath": "/images/phone-active.png"
}
]
},
/**
* 组件的方法列表
*/
methods: {
onChange(event) {
// event.detail 的值为当前选中项的索引
this.setData({ active: event.detail });
},
}
})
第二步:在index.wxss写如下配置
/* custom-tab-bar/index.wxss */
.van-tabbar-item{
--tabbar-item-margin-bottom:0;
}
- 动态监听数字的变化
向用Mobx将数据传递过来
index.js
import { storeBindingsBehavior } from 'mobx-miniprogram-bindings'
import { store } from "../store/store"
behaviors:[storeBindingsBehavior],
storeBindings:{
// 第四步: 指定要绑定的数据源Store
store,
// 第五步: 指定要绑定的字段数据
fields:{
sum:'sum' // 绑定字段的第三种方式
},
// 第六步: 指定绑定的方法
actions:{
}
},
observers:{
'sum':function(newSum){
console.log(newSum)
this.setData({
// 1这里我们不用写 this.data 直接写对象名即可。因为已经帮我们自动填充了
'list[1].info':newSum
})
}
},
methods: {
onChange(event) {
// event.detail 的值为当前选中项的索引
this.setData({ active: event.detail });
wx.switchTab({
url: this.data.list[event.detail].pagePath,
})
},
}
- 解决光标不一致的情况
store.js
共享数据和方法
// 在这个js文件中,专门来常见Store的实列对象
import { action, observable } from 'mobx-miniprogram'; // 引入MobX
// 抛出 Mobx
export const store = observable({
// 共享下面的变量
activeTabBrIndex:0,
// (1).共享数据字段
numA:1,
numB:2,
// (2).计算属性 -》 关键字 get 表示这个计算属性是只能 读取的。
get sum(){
return this.numA+this.numB
},
// (3).actions 方法 用来修改store中的数据
updateNum1:action(function(step){ // 第一个是 自定义方法名, 第二个是 action
this.numA+=step
}),
updateNum2:action(function(step){
this.numB+=step
}),
updateActiveTabBrIndex:action(function(indx){
this.activeTabBrIndex=indx
})
})
// custom-tab-bar/index.js
import { storeBindingsBehavior } from 'mobx-miniprogram-bindings'
import { store } from "../store/store"
Component({
behaviors:[storeBindingsBehavior],
storeBindings:{
// 第四步: 指定要绑定的数据源Store
store,
// 第五步: 指定要绑定的字段数据
fields:{
sum:'sum', // 绑定字段的第三种方式
active1:'activeTabBrIndex'
},
// 第六步: 指定绑定的方法
actions:{
updateActive1:'updateActiveTabBrIndex'
}
},
observers:{
'sum':function(newSum){
console.log(newSum)
this.setData({
// 1这里我们不用写 this.data 直接写对象名即可。因为已经帮我们自动填充了
'list[1].info':newSum
})
}
},
"options":{
styleIsolation:'shared'
},
data: {
active: 0,
list: [
{
"pagePath": "/pages/home/home",
"text": "首页",
"iconPath": "/images/index.png",
"selectedIconPath": "/images/index-active.png"
},
{
"pagePath": "/pages/message/message",
"text": "信息",
"iconPath": "/images/mail.png",
"selectedIconPath": "/images/mail-active.png",
info:2
},
{
"pagePath": "/pages/contact/contact",
"text": "电话",
"iconPath": "/images/phone.png",
"selectedIconPath": "/images/phone-active.png"
}
]
},
methods: {
onChange(event) {
// event.detail 的值为当前选中项的索引
this.setData({ active: event.detail });
this.updateActive1(event.detail)
wx.switchTab({
url: this.data.list[event.detail].pagePath,
})
},
}
})
<van-tabbar active="{{ active1 }}" 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: 30px; height: 18px;"
/>
<image
slot="icon-active"
src="{{item.selectedIconPath}}"
mode="aspectFit"
style="width: 30px; height: 18px;"
/>
{{item.text}}
van-tabbar-item>
van-tabbar>
active-color="#13A7A0"