微信小程序-(十)自定义组件

本文最后更新于:April 2, 2022 pm

微信小程序,小程序的一种,英文名Wechat Mini Program,是一种不需要下载安装即可使用的应用,它实现了应用“触手可及”的梦想,用户扫一扫或搜一下即可打开应用。也体现了“用完即走”的理念,用户不用关心是否安装太多应用的问题。应用将无处不在,随时可用,但又无需安装卸载。对于开发者而言,微信小程序开发门槛相对较低,难度不及APP,能够满足简单的基础应用,适合生活服务类线下商铺以及非刚需低频应用的转换。

目录

创建组件

在根目录下创建一个 components 文件夹(和 pages等文件夹同级),然后在其中再创建一个文件夹(为方便区分可以命令为组件的名称),这里以 test 为例。然后选中文件夹 test 右键 -> 新建Component 。然后会自动创建好四种类型的文件。

引用组件

局部引用

需要时再引用。在需要引用组件的页面的 .json 文件夹中添加需要引用的组件,如下:

1
2
3
4
//home.json
"usingComponents": {
"test":"/components/test/test"
},

其中,以键值对的方式添加组件。键 为 test ,也表示引用时用的名称,值为组件的路径。 如:

1
2
<!--pages/home/home.wxml-->
<test></test>

全局引用

一处配置,全局通用。

app.json 全局配置文件中引用组件。

1
2
3
4
5
6
7
8
9
10
11
12
{
"pages": [],
"window": {},
"tabBar": {},
"usingComponents": { //要引用的组件
"testt":"/components/test/test"
},
"style": "v2",
"sitemapLocation": "sitemap.json",
"lazyCodeLoading": "requiredComponents"
}

配置方式同局部引用配置一样。

组件和页面的区别

从表明上看,组件和页面都是由四个不同类型的文件组成的。但是,组件和页面的 .js 文件和 .json 文件有明显的不同:

  • 组件的 .json 文件中需要声明 "component": true 属性。

  • 组件的 .js 文件中调用的是 Component({}) 函数;而页面调用的是 Page({}) 函数。

  • 组件的事件处理函数需要定义到 .js 文件的 methods 节点中。

组件的样式

组件样式是具有隔离性的,即组件与组件之间是不会相互影响的(样式),小程序和组件之间也是不会相互影响的。

  • app.wxss 中的全局样式对组件无效。
  • 只有class选择器会有样式隔离效果(不会相互影响),id选择器、属性选择器、标签选择器不受样式隔离的影响(会相互影响)。

所以,在组件和引用组件的页面中建议使用class选择器,而不要使用id、属性、标签选择器。

修改组件的样式隔离选项

默认情况下,自定义组件的样式隔离特性能够防止组件内外样式互相干扰的问题。但有时,希望在外界能够控制组件内部的样式,这时,可以通过 styleIsolation 修改组件的样式隔离选项,如在组件的 .js 文件中添加:

1
2
3
4
5
6
7
8
9
10
11
12
// components/test/test.js
Component({
options:{
styleIsolation: 'isolated'
},
/**
* 组件的属性列表
*/
properties: {

},
})

或者在组件的 .json 文件中添加:

1
2
3
{
"styleIsolation": "isolated"
}

styleIsolation 的值有三个:

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

组件参数

在小程序组件中,properties 是组件的对外属性,用来接受外界传递到组件中的数据。

属性定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// components/test/test.js
Component({

/**
* 组件的属性列表
*/
properties: {
max: { //完整定义属性的方式(可以设置默认值)
type: Number, //属性值的类型
value: 10 //默认值
},
max: Number //简化方式(不能指定属性默认值)
},
})

<!--pages/home/home.wxml-->
<test max="25"></test>

数据监听器

用于监听和相应任何属性和数据字段的变化,从而执行特定的操作。类似于vue中的 watch。

简单监听器

1
2
3
4
5
6
7
8
9
// components/test/test.js
Component({

observers:{
'字段1,字段2':function(字段1的新值,字段2的新值){
//处理
}
},
})

对象属性

1
2
3
4
5
6
7
8
9
// components/test/test.js
Component({

observers:{
'对象.属性a,对象.属性b':function(属性a的新值,属性b的新值){
//处理
}
},
})

插槽

插槽就是子组件中的提供给父组件使用的一个占位符,用 <slot></slot> 表示,父组件可以在这个占位符中填充任何模板代码,如 HTML、组件等,填充的内容会替换子组件的 <slot></slot>标签。

单个插槽

  • 组件中
1
2
3
4
5
6
<!--components/test/test.wxml-->
<view>
<text>这里是组件中的内容</text>
<slot></slot> //插槽,占位符
</view>

  • 引用组件时
1
2
3
4
5
<!--pages/message/message.wxml-->

<testt>
<view>这是插槽中的内容</view> <!-- 填入插槽中的内容-->
</testt>

多个插槽

若需要使用多个插槽,则需要到组件的 .js 文件中进行设置启用:

1
2
3
4
5
6
7
// components/test/test.js
Component({

options:{
multipleSlots: true //开启多个插槽
},
})

定义多个插槽

使用多个插槽时,以不同的 name 来区分不同的插槽。

1
2
3
4
5
6
7
<!--components/test/test.wxml-->
<view>
<text>这里是组件中的内容</text>
<slot name="bf"></slot>
<slot name="af"></slot>
</view>

使用时,需要指定插入到哪一个插槽中,使用 slot 属性

1
2
3
4
5
6
<!--pages/message/message.wxml-->

<testt>
<view slot="af">这是插槽af中的内容</view> <!--插槽到name为af的插槽中-->
<view slot="bf">这是插槽bf中的内容</view> <!--插槽到name为bf的插槽中--b
</testt>

父子组件通信

通信方式

父子组件之间通信的三种方式:属性绑定(只能用于父组件向子组件)、事件绑定、获取组件实例。

属性绑定

父向子传值。用于父组件向子组件的指定属性设置数据,仅能设置JSON兼容的数据。只能传递普通类型的数据,无法将方法传递给子组件。示例:

父组件

message.wxml:

1
2
3
<!--pages/message/message.wxml-->

<testt Cnt="{{Pcnt}}"></testt> <!--Pcnt为父组件的数据。Cnt为子组件中的接受参数名-->

message.js:

1
2
3
4
5
6
7
8
9
10
11
// pages/message/message.js
Page({

/**
* 页面的初始数据
*/
data: {
ups:'loong',
Pcnt: 23
}
})

子组件

test.wxml:

1
2
3
4
5
6
<!--components/test/test.wxml-->
<view>
<text>这里是组件中的内容</text>

<view>这是从父组件中传过来的值:{{Cnt}}</view>
</view>

test.js:

1
2
3
4
5
6
7
8
9
10
// components/test/test.js
Component({
/**
* 组件的属性列表
*/
properties: {
Cnt:Number //参数列表
}
})

事件绑定

子向父传值。用于子组件向父组件传递数据(任意的数据)。但相较于属性绑定,步骤较麻烦点。

  • 先在父组件.js 文件中,定义一个函数,这个函数将会通过自定义事件的形式,传递给子组件。
  • 再在父组件.wxml 文件中,通过自定义事件的形式,将上一步骤定义的函数引用,传递给子组件。
  • 然后在子组件.js 文件中,通过调用 this.triggerEvent('自定义事件名称',{参数对象}),将数据发送到父组件。
  • 父组件.js 文件中,通过 e.detail 获取到子组件传递过来的数据。

示例:

  1. 父组件的JS中定义函数。
1
2
3
4
5
6
7
// pages/message/message.js
Page({

PMShow(){
console.log('这是父组件中的函数!');
}
})
  1. 父组件的 WXML文件中定义函数的引用,并将引用传递给子组件。
1
2
3
4
5
6
7
8
<!--pages/message/message.wxml-->

<!-- 使用 bind:自定义事件名称 -->
<testt bind:SMshow="PMShow"></testt>
<!-- 使用 bind自定义事件名称 -->
<testt bindSMshow="PMShow"></testt>

<!-- 更推荐第一种 -->
  1. 子组件的JS文件中,通过调用 this.triggerEvent('自定义事件名称',{参数对象}),将数据发送到父组件。
1
2
3
4
5
6
7
8
9
10
11
12
13
// components/test/test.js
Component({

/**
* 组件的方法列表
*/
methods: {
SonToP(){
this.triggerEvent('SMshow',{value:23}) //SMshow是在父组件的wxml中定义的自定义事件名称
}
}
})

  1. 父组件的 JS文件中,通过 e.detail 获取到子组件传递过来的数据。
1
2
3
4
5
6
7
8
9
// pages/message/message.js
Page({

PMShow(e){ //接受子组件传过来的数据
console.log('这是父组件中的函数!');
console.log('子组件中的值为'+e.detail.value);
},

})

只需要在子组件中触发方法即可。

获取组件实例

在父组件中可以通过 this.selectComponent("id或class选择器") 获取子组件实例对象。可以直接访问子组件的任意数据和方法。调用时,需要传入一个选择器。

子组件中的数据和方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// components/test/test.js
Component({

/**
* 组件的初始数据
*/
data: {
SonName: 'ssss',
SonAge:11
},

/**
* 组件的方法列表
*/
methods: {
SonM1(){
console.log('子组件中的方法一');
},
SonM2(){
console.log('子组件中的方法二');
}
}
})

父组件中获取子组件实例

wxml:

1
2
3
4
<!--pages/message/message.wxml-->

<testt id="sonA" class="son"></testt>
<button bindtap="GetSon">点击获取子组件实例</button>

js:

1
2
3
4
5
6
7
8
9
10
11
  // pages/message/message.js
Page({

GetSon(){
const sons = this.selectComponent('.son') //也可以使用id选择器
console.log('子组件中的age:'+sons.data.SonAge);
console.log('子组件中的name:'+sons.data.SonName);
sons.SonM1()
sons.SonM2()
},
})

behaviors

用于实现组件间代码共享的特性,类似于Vue中的 “mixins”。每个behavior可以包含一组属性、数据、生命周期函数和方法。组件引用时,它的属性、数据和方法会被合并到组件中。每个组件可以引用多个behavior,behavior也可以引用其他behavior。

创建behavior

调用 Behavior(Object object)方法即可创建一个共享的behavior实例对象,可供所有的组件使用:

新建一个文件夹,并创建一个JS文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// behaviors/myBehavior1.js

module.exports = Behavior({
data:{
PublicName: 'www.tothefor.com'
},
properties:{},
methods:{
PublicM(){
console.log('公共方法');
}
}
})

导入并使用behavior

在组件中,使用 require()方法导入需要的 Behavior,挂载后即可访问Behavior中的数据和方法。示例:

1
2
3
4
5
6
7
// components/test/test.js
const mb = require("../../behaviors/myBehavior1")
Component({
behaviors:[mb],

})

使用:

1
2
3
4
<!--components/test/test.wxml-->

<view>{{PublicName}}</view>
<button bindtap="PublicM">点击触发</button>

Behavior中所有可用的节点

可用节点 类型 必填 描述
properties Object Map 同组件的属性
data Object 同组件的数据
methods Object 同自定义组件的方法
behaviors String Array 引入其他的Behavior
created Function 生命周期函数
attached Function 生命周期函数
ready Function 生命周期函数
moved Function 生命周期函数
detached Function 生命周期函数