小程序>微信小程序组件间通信与传值的全面解析
在小程序>微信小程序中,组件之间的传值主要通过以下几种方式实现,每种方式都有其适用的场景和数据类型:
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文件中进行注册:
{"usingComponents": {"xbutton":"/components/xbutton/xxbutton","xbrother":"/components/xbrother/xbrother"}
}
父组件 WXML:
<!-- 这里的标签child-component就是子组件的名称 -->
<!-- 属性message、list都是自定义属性。这两个属性需要在子组件的.js文件中的properties中接收,在下面会提到 --><child-component message="{{parentData}}" list="{{items}}"></child-component>
父组件 JS:
Page({// 基本的定义数据data: {parentData: '来自父组件的消息',items: ['衣服', '裤子', '帽子']}
});
子组件 JS:
Component({// 在父组件中定义的的两个自定义属性,在子组件中的properties选项中进行接收// 接收到父组件的值,可以当成这个组件的数据使用,在WXML文件中使用与data中的数据使用一样properties: {message: {type: String,value: '默认值'},list: {type: Array,value: []}}
});
子组件WXML:
<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:
Component({// methods方法区与上面的properties区、data区并列methods: {// 在子组件中定义的事件,当这个事件触发的时候,会向父组件发送一个携带有数据的方法handleClick() {// this.triggerEvent事件的两个参数,第一个是自定义事件的名字,第二个是发送的数据this.triggerEvent('customEvent', { message: '子组件传递的消息' });}}
});
子组件 WXML:
<!-- bind:tap为点击事件,当点击时就会触发上面的handleClick方法就会触发了 -->
<view bind:tap="handleClick">点击我</view>
父组件 WXML:
<!-- 当时在子组件中用this.triggerEvent发送的customEvent事件,就在父组件中用到。 -->
<!-- 用一个方法去接收子组件发送过来的参数 -->
<!-- 这个自定义事件是需要绑在子组件child-component上面的,注意别绑错了 -->
<child-component bind:customEvent="handleCustomEvent"></child-component>
父组件 JS:
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:
<button bind:tap="handleClick">点击我向父组件传值
</button>
发起者组件JS:
// components/xbutton/xbutton.js
Component({properties: {},data: {},methods: {handleClick(){// 向父组件发送事件以及信息this.triggerEvent("fromChildEventName",`给兄弟组件传的值, 先交给父组件吧`)}}
})
共同的父组件WXML:
<view><!-- 组件xbutton就相当于“发起者”,利用了子向父传值 --><xbutton bind:fromChildEventName="acceptMsg"></xbutton><!-- 组件xbrother就相当于“接收者”,利用了父向子传值 --><xbrother two-brother="{{childrenmsg}}"></xbrother>
</view>
共同的父组件JS:
Page({data: {// 用一个数据变量准备将发起者传过来的数据存起来childrenmsg:""},acceptMsg(data){console.log("子组件传过来的数据:",data,data.detail)const childrenmsg = data.detail// 将发起者传过来的数据存起来this.setData({childrenmsg})}
})
接收者组件WXML:
<view>兄弟组件通过父组件传过来的值:{{twoBrother}}</view>
接收者组件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
等。
<button bindtap="handleTap" data-id="123" data-name="Tom">点击我</button>
2.2 在事件处理函数中获取数据
在事件处理函数中,可以通过 event.currentTarget.dataset
获取 data-*
属性传递的数据。
Page({handleTap(event) {console.log(event.currentTarget.dataset.id); // 输出:123console.log(event.currentTarget.dataset.name); // 输出:Tom}
});
3. 注意事项
-
动态绑定数据 如果需要绑定动态数据,可以使用
{{}}
语法。例如:HTML复制
<button bindtap="handleTap" data-id="{{itemId}}" data-name="{{itemName}}">点击我</button>
在页面的
data
中定义itemId
和itemName
:Page({data: {itemId: 123,itemName: "Tom"} });
-
事件对象的
dataset
属性event.currentTarget.dataset
是一个对象,包含了所有通过data-*
传递的数据。例如:handleTap(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:
<view wx:for="{{items}}" bindtap="handleTap" data-id="{{item.id}}" data-name="{{item.name}}">{{item.name}}
</view>
JS:
Page({data: {items: [{ id: 1, name: "Item 1" },{ id: 2, name: "Item 2" }]},handleTap(event) {console.log(event.currentTarget.dataset.id); // 输出:1 或 2console.log(event.currentTarget.dataset.name); // 输出:Item 1 或 Item 2}
});
5.2 自定义组件中的使用
子组件 WXML:
<button bindtap="handleTap" data-id="123">点击我</button>
子组件 JS:
Component({methods: {handleTap(event) {this.triggerEvent("customEvent", event.currentTarget.dataset);}}
});
父组件 WXML:
<custom-component bind:customEvent="handleCustomEvent"></custom-component>
父组件 JS:
Page({handleCustomEvent(event) {console.log(event.detail.id); // 输出:123}
});
通过 data-*
属性,开发者可以在事件处理中灵活传递和获取数据,从而实现复杂的功能。
5. 直接访问子组件实例
在小程序>微信小程序中,this.selectComponent
是一个非常强大的方法,用于在父组件中获取子组件的实例。通过这个实例,父组件可以直接访问子组件的内部数据、方法,甚至触发子组件的行为。以下是详细的使用方法和注意事项:
1. this.selectComponent
的基本用法
this.selectComponent
方法通过选择器(selector
)来获取子组件的实例。选择器可以是类名(.class
)或 ID(#id
)。
语法:
const componentInstance = this.selectComponent(selector);
selector
:用于选择子组件的选择器,可以是类名(如.my-component
)或 ID(如#my-component
)。- 返回值:返回一个组件实例对象,如果未找到匹配的组件,则返回
null
。
示例:
假设有一个子组件 child-component
,其 WXML 文件如下:
<view id="child" class="child-component">子组件内容</view>
在父组件中,可以通过以下方式获取子组件实例:
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
:
Component({behaviors: ['wx://component-export'],export: {myField: 'myValue'}
});
父组件获取子组件实例时,返回的是自定义的对象:
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
,适用于需要直接操作子组件的场景。