微信小程序组件间通信与传值的全面解析
在微信小程序中,组件之间的传值主要通过以下几种方式实现,每种方式都有其适用的场景和数据类型:
1. 父组件向子组件传值(父传子)
父组件可以通过 properties
将数据传递给子组件。子组件在 properties
中定义接收的属性及其类型。
子组件创建方式(以下通用)
子组件的创建方式与普通组件的创建方式有所不同,他们的最大区别就是.js文件的配置不同,以及json文件中的配置不同
-
首先要在文件夹的根目录下创建一个components文件夹
-
接下来就在components文件夹中创建component文件 ,注意这里不是创建Page
-
components中的.js文件与之前的pages下的文件夹中的.js文件还是有差别的,各属性可以通过名字知道他是干什么的
数据类型
- 基本数据类型 :
String
、Number
、Boolean
、Null
、Undefined
。 - 复杂数据类型 :
Object
、Array
、Function
(自基础库版本 2.0.9 开始支持)。
示例代码
父组件 JSON:
在父组件中要用到子组件,首先需要在父组件中的JSON文件中进行注册:
json
{
"usingComponents": {
"xbutton":"/components/xbutton/xxbutton",
"xbrother":"/components/xbrother/xbrother"
}
}
父组件 WXML:
html
<!-- 这里的标签child-component就是子组件的名称 -->
<!-- 属性message、list都是自定义属性。这两个属性需要在子组件的.js文件中的properties中接收,在下面会提到 -->
<child-component message="{{parentData}}" list="{{items}}"></child-component>
父组件 JS:
javascript
Page({
// 基本的定义数据
data: {
parentData: '来自父组件的消息',
items: ['衣服', '裤子', '帽子']
}
});
子组件 JS:
javascript
Component({
// 在父组件中定义的的两个自定义属性,在子组件中的properties选项中进行接收
// 接收到父组件的值,可以当成这个组件的数据使用,在WXML文件中使用与data中的数据使用一样
properties: {
message: {
type: String,
value: '默认值'
},
list: {
type: Array,
value: []
}
}
});
子组件WXML:
vue
<view>
<!-- 接受父组件的值,在WXML中使用 -->
<text>父组件信息-message:{{message}}</text>
<view wx:for="{{list}}" wx:key="index">{{item}}</view>
</view>
2. 子组件向父组件传值(子传父)
在vue中:
子组件可以通过 this.$emit
触发自定义事件,并将数据传递给父组件。父组件通过绑定事件监听器接收数据。
在微信小程序中:
子组件可以通过 this.triggerEvent
触发自定义事件,并将数据传递给父组件。父组件通过绑定事件监听器接收数据。与vue中的方法基本相同,自定义事件的参数都相同。
数据类型
- 任意数据类型 :可以传递任意类型的数据,包括
String
、Number
、Object
、Array
等。
示例代码
子组件 JS:
javascript
Component({
// methods方法区与上面的properties区、data区并列
methods: {
// 在子组件中定义的事件,当这个事件触发的时候,会向父组件发送一个携带有数据的方法
handleClick() {
// this.triggerEvent事件的两个参数,第一个是自定义事件的名字,第二个是发送的数据
this.triggerEvent('customEvent', { message: '子组件传递的消息' });
}
}
});
子组件 WXML:
html
<!-- bind:tap为点击事件,当点击时就会触发上面的handleClick方法就会触发了 -->
<view bind:tap="handleClick">点击我</view>
父组件 WXML:
html
<!-- 当时在子组件中用this.triggerEvent发送的customEvent事件,就在父组件中用到。 -->
<!-- 用一个方法去接收子组件发送过来的参数 -->
<!-- 这个自定义事件是需要绑在子组件child-component上面的,注意别绑错了 -->
<child-component bind:customEvent="handleCustomEvent"></child-component>
父组件 JS:
javascript
Page({
// 通过子组件发送的事件,在父组件用方法handleCustomEvent(event)去触发,其中参数event就是子组件发来的数据
handleCustomEvent(event) {
console.log(event.detail.message); // 接收子组件传递的数据
}
});
3. 兄弟组件之间的传值(子向子)
兄弟组件之间的传值没有直接的方法,需要通过上面两种传值方式的结合从而实现,下面是思路:
- 为了方便讲述。其中一个发送数据的组件主动的一方,咱们可以把它叫做"发起者",另一个叫做"接收者"
- 首先,发起者把接收者想要的数据,通过子向父传值的方式,用this.triggerEvent方法自定义一个事件,把想要的数据发给,他们共同的父组件。
- 接着,在父组件中将接收到的数据,存到data区的某个数据中。
- 然后,运用父向子传值的方法,将data区中存的发起者发来的数据,传给接收者。
- 最后,在接收者中的properties区去接收这个数据,在上讲到过,不会的可以再去上面仔细研究一下
思路成立,接下来进入实战:
数据类型
- 基本数据类型 :
String
、Number
、Boolean
、Null
、Undefined
。 - 复杂数据类型 :
Object
、Array
、Function
(自基础库版本 2.0.9 开始支持)。
示例代码
发起者组件WXML:
vue
<button bind:tap="handleClick">
点击我向父组件传值
</button>
发起者组件JS:
js
// components/xbutton/xbutton.js
Component({
properties: {
},
data: {
},
methods: {
handleClick(){
// 向父组件发送事件以及信息
this.triggerEvent("fromChildEventName",`给兄弟组件传的值, 先交给父组件吧`)
}
}
})
共同的父组件WXML:
vue
<view>
<!-- 组件xbutton就相当于"发起者",利用了子向父传值 -->
<xbutton bind:fromChildEventName="acceptMsg"></xbutton>
<!-- 组件xbrother就相当于"接收者",利用了父向子传值 -->
<xbrother two-brother="{{childrenmsg}}"></xbrother>
</view>
共同的父组件JS:
js
Page({
data: {
// 用一个数据变量准备将发起者传过来的数据存起来
childrenmsg:""
},
acceptMsg(data){
console.log("子组件传过来的数据:",data,data.detail)
const childrenmsg = data.detail
// 将发起者传过来的数据存起来
this.setData({
childrenmsg
})
}
})
接收者组件WXML:
vue
<view>兄弟组件通过父组件传过来的值:{{twoBrother}}</view>
接收者组件JS:
js
// components/xbrother/xbrother.js
Component({
// 接收发起者通过父组件传过来的值
properties: {
twoBrother:{
type:String,
value:""
}
},
data: {
},
methods: {
}
})
4. 通过 data-\*
属性传递数据
在微信小程序中,data-*
属性是一种非常灵活的机制,用于在绑定事件时传递自定义数据。以下是关于 data-*
属性的详细讲解:
1. 什么是 data-\*
属性?
data-*
属性是一种自定义数据属性,允许开发者在 HTML 元素上附加任意数据。这些数据在触发事件时会被自动传递给事件处理函数,从而实现事件传参。
2. 如何使用 data-\*
属性传递数据?
2.1 在 WXML 中绑定 data-\*
属性
在 WXML 文件中,可以通过 data-*
属性将数据绑定到事件触发的元素上。*
可以是任意自定义的属性名,例如 data-id
、data-name
等。
html
<button bindtap="handleTap" data-id="123" data-name="Tom">点击我</button>
2.2 在事件处理函数中获取数据
在事件处理函数中,可以通过 event.currentTarget.dataset
获取 data-*
属性传递的数据。
javascript
Page({
handleTap(event) {
console.log(event.currentTarget.dataset.id); // 输出:123
console.log(event.currentTarget.dataset.name); // 输出:Tom
}
});
3. 注意事项
-
动态绑定数据 如果需要绑定动态数据,可以使用
{``{}}
语法。例如:HTML复制
html<button bindtap="handleTap" data-id="{{itemId}}" data-name="{{itemName}}">点击我</button>
在页面的
data
中定义itemId
和itemName
:javascriptPage({ data: { itemId: 123, itemName: "Tom" } });
-
事件对象的
dataset
属性event.currentTarget.dataset
是一个对象,包含了所有通过data-*
传递的数据。例如:javascripthandleTap(event) { console.log(event.currentTarget.dataset); // { id: "123", name: "Tom" } }
-
data-\*
属性的命名规范- 属性名必须以
data-
开头。 - 属性值可以是字符串、数字或布尔值。
- 属性名必须以
-
currentTarget
和target
的区别event.currentTarget
指向绑定事件的元素。event.target
指向触发事件的元素。- 在事件冒泡时,
currentTarget
和target
可能不同。
4. 使用场景
data-*
属性常用于以下场景:
- 在按钮点击事件中传递额外参数。
- 在列表渲染中为每个列表项绑定唯一标识。
- 在自定义组件中传递数据。
5. 示例
5.1 动态绑定数据
WXML:
html
<view wx:for="{{items}}" bindtap="handleTap" data-id="{{item.id}}" data-name="{{item.name}}">
{{item.name}}
</view>
JS:
javascript
Page({
data: {
items: [
{ id: 1, name: "Item 1" },
{ id: 2, name: "Item 2" }
]
},
handleTap(event) {
console.log(event.currentTarget.dataset.id); // 输出:1 或 2
console.log(event.currentTarget.dataset.name); // 输出:Item 1 或 Item 2
}
});
5.2 自定义组件中的使用
子组件 WXML:
html
<button bindtap="handleTap" data-id="123">点击我</button>
子组件 JS:
javascript
Component({
methods: {
handleTap(event) {
this.triggerEvent("customEvent", event.currentTarget.dataset);
}
}
});
父组件 WXML:
html
<custom-component bind:customEvent="handleCustomEvent"></custom-component>
父组件 JS:
javascript
Page({
handleCustomEvent(event) {
console.log(event.detail.id); // 输出:123
}
});
通过 data-*
属性,开发者可以在事件处理中灵活传递和获取数据,从而实现复杂的功能。
5. 直接访问子组件实例
在微信小程序中,this.selectComponent
是一个非常强大的方法,用于在父组件中获取子组件的实例。通过这个实例,父组件可以直接访问子组件的内部数据、方法,甚至触发子组件的行为。以下是详细的使用方法和注意事项:
1. this.selectComponent
的基本用法
this.selectComponent
方法通过选择器(selector
)来获取子组件的实例。选择器可以是类名(.class
)或 ID(#id
)。
语法:
javascript
const componentInstance = this.selectComponent(selector);
selector
:用于选择子组件的选择器,可以是类名(如.my-component
)或 ID(如#my-component
)。- 返回值 :返回一个组件实例对象,如果未找到匹配的组件,则返回
null
。
示例:
假设有一个子组件 child-component
,其 WXML 文件如下:
html
<view id="child" class="child-component">子组件内容</view>
在父组件中,可以通过以下方式获取子组件实例:
javascript
Page({
// 生命周期函数--监听页面加载
onLoad() {
const childComponent = this.selectComponent("#child");
if (childComponent) {
console.log(childComponent.data); // 访问子组件的 data 数据
childComponent.someMethod(); // 调用子组件的方法
} else {
console.error("未找到子组件实例");
}
}
});
2. 获取子组件实例的用途
通过 this.selectComponent
获取子组件实例后,可以实现以下功能:
- 访问子组件的内部数据 :
- 使用
componentInstance.data
或componentInstance.properties
访问子组件的内部数据。
- 使用
- 调用子组件的方法 :
- 直接通过
componentInstance.someMethod()
调用子组件中定义的方法。
- 直接通过
- 动态修改子组件的数据 :
- 使用
componentInstance.setData()
修改子组件的内部数据。
- 使用
3. 注意事项
- 选择器的范围 :
this.selectComponent
的选择器范围仅限于当前页面或组件内部。 . 组件实例的返回值:- 默认情况下,
this.selectComponent
返回的是子组件的实例对象。 - 如果需要自定义返回值,可以在子组件中使用
wx://component-export
行为。
自定义返回值示例:
在子组件中使用 wx://component-export
:
javascript
Component({
behaviors: ['wx://component-export'],
export: {
myField: 'myValue'
}
});
父组件获取子组件实例时,返回的是自定义的对象:
javascript
const childComponent = this.selectComponent("#child");
console.log(childComponent.myField); // 输出:myValue
- 跨组件通信的限制 :
- 默认情况下,小程序与插件之间、不同插件之间的组件无法通过
this.selectComponent
获取实例(返回null
)。 - 如果需要跨组件通信,需要在子组件中明确允许通过
wx://component-export
。
- 默认情况下,小程序与插件之间、不同插件之间的组件无法通过
4. 使用场景
- 动态调用子组件方法:父组件可以根据用户操作动态调用子组件的方法。
- 访问子组件数据:父组件可以获取子组件的内部状态,用于同步或验证。
- 组件间通信 :在复杂的组件结构中,
this.selectComponent
是一种高效的通信方式。
通过 this.selectComponent
,开发者可以灵活地操作子组件的实例,实现复杂的组件间交互。
总结
- 父传子 :通过
properties
传递,支持基本和复杂数据类型。 - 子传父 :通过
this.triggerEvent
触发事件,支持任意数据类型。 - 兄弟传:通过上面两种方法结合,支持基本和复杂数据类型。
- 事件传参 :通过
data-*
属性传递自定义数据,支持基本数据类型。 - 直接访问子组件实例 :通过
this.selectComponent
,适用于需要直接操作子组件的场景。
这些方式共同构成了微信小程序中组件间通信的完整体系,可以根据具体需求选择合适的方式进行数据传递。