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

本文最后更新于: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 否 生命周期函数