01_组件通信
思路分析:
1.总述知道的所有方式
2.按组件关系阐述使用场景
回答范例:
1.组件通信的方式有下面的8种
- props
- e m i t / ∗ ∗ emit/** emit/∗∗on**
- ** c h i l d r e n ∗ ∗ / children**/ children∗∗/parent
- a t t r s / ∗ ∗ attrs/** attrs/∗∗listeners**
- provide+inject
- ref
- $root
- eventbus(然后vue3中已经不推荐我们使用eventbus了,因为其麻烦程度不亚于vuex了,而且多人开发时更加难维护)
- vuex/pinia
在vue3中
$on在vue3中被废除了:
Vue 3废除$on
等方法是为了简化API、提高性能,并更好地支持Composition API和类型推断。通过推荐使用v-on
指令和Composition API的方式来监听事件,可以提供更一致和直观的编程体验。
$children:也被废除了
在Vue 3中,$children
被废除的原因是出于性能和响应式数据的可预测性考虑。Vue 3的设计目标之一是提高性能和减少不必要的响应式追踪。
$children
是一个在Vue 2中提供的实例属性,用于访问组件实例的直接子组件。然而,Vue 2中的$children
存在一些问题:
- 响应式数据的可预测性:在Vue 2中,
$children
返回一个动态数组,它会随着组件的渲染和销毁而动态变化。这导致在模板中使用$children
的时候,无法准确预测子组件的数量和顺序,从而影响模板的可预测性和可维护性。 - 性能问题:Vue 2中的
$children
是一个响应式属性,它会追踪组件实例的子组件,并在子组件发生变化时触发重新渲染。这意味着即使在模板中没有直接使用$children
,它仍然会对组件的性能产生负面影响,因为每次子组件发生变化时都会触发重新渲染。
$listeners也被废除了
在Vue 2中,$listeners
是一个特殊属性,用于获取父组件传递给子组件的所有事件监听器。它是一个包含了所有父组件传递的事件监听器的对象,可以通过v-on="$listeners"
的方式将这些事件监听器绑定到子组件上。
然而,Vue 2中的$listeners
存在一些问题:
- 性能问题:由于
$listeners
会包含所有父组件传递的事件监听器,即使子组件并没有使用这些监听器,也会对组件的性能产生负面影响。这是因为Vue 2中的组件更新机制会对$listeners
进行遍历和处理。 - 不明确的事件继承关系:Vue 2中的
$listeners
会将父组件的所有事件监听器传递给子组件,这导致了事件继承关系的不明确性。子组件可能会接收到一些并不需要的事件监听器,从而增加了组件的复杂性和维护成本。
2.根据组件之间的关系讨论组件通信最为清晰有效
父子
props、 e m i t 、 emit、 emit、parent、 r e f 、 ref、 ref、attrs
兄弟:
$parent $root eventbus vuex
跨层级
eventbus vuex provide+inject
代码演示
props:
用于父亲向孩子传递数据
//在父组件中
<son name:'jack' age='18' sex:'男'></son>
//在子组件接收
props:['name','age','sex']//简单接收
props:{ //也可以把props写出对象的形式,这样可以对类型做限制
"name":{
type:String,//限制类型
required:true//是否必须
},
"age":{
type:NUmber,
default:18//如果不传,就为默认值
},
"sex":{
type:String,
default:'男'
}
}
$emit
子组件可以使用 $emit,让父组件监听到自定义事件,然后收到子组件传递的数据
子组件son:
<button @click='select(`大连`)'>点击此处将‘大连’发射给父组件</button>
methods:{
select(val) {
this.$emit('showCityName',val);//select事件触发后,自动触发showCityName事件
}
}
父组件:
<son @showCityName="updateCity" :sendData="toCity"></son>
methods:{
updateCity(data){//触发子组件城市选择-选择城市的事件
this.toCity = data.cityname;//改变了父组件的值
console.log('toCity:'+this.toCity)
}
}
$on
使用 $on(eventName) 监听事件
使用 $emit(eventName) 触发事件
c h i l d r e n 和 children和 children和parent
$children
属性是一个数组,包含当前组件实例的所有直接子组件。可以通过this.$children
来访问。
<template>
<div>
<child-component></child-component>
<child-component></child-component>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
mounted() {
console.log(this.$children); // 打印子组件实例数组
}
}
</script>
$parent
属性是指向当前组件实例的父组件实例的引用。可以通过this.$parent
来访问。这可以用于在子组件中访问父组件的属性或调用父组件的方法。
以下是一个使用$parent
属性的示例:
<template>
<div>
<child-component></child-component>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
data() {
return {
message: 'Hello from parent component!'
}
}
}
</script>
<template>
<div>
<p>{{ $parent.message }}</p>
<button @click="$parent.someMethod">Call Parent Method</button>
</div>
</template>
<script>
export default {
mounted() {
console.log(this.$parent); // 打印父组件实例
}
}
</script>
在上面的示例中,子组件通过$parent
属性访问了父组件的message
属性,并在模板中显示它。另外,子组件中的按钮点击事件通过$parent
调用了父组件中的someMethod
方法。
需要注意的是,使用$children
和$parent
可以方便地在组件之间传递数据和进行通信,但在大型应用中,过多地依赖这两个属性可能会导致组件之间的耦合性增加。因此,最好在设计组件之间的通信时考虑使用更合适的方式,如Vuex状态管理.
a t t r s / ∗ ∗ attrs/** attrs/∗∗listeners**
在Vue.js中,$attrs
和$listeners
是用于在组件中传递属性和监听器的特殊属性。
$attrs
属性是一个对象,包含了父组件传递给当前组件的所有非特定属性(即非props)。它可以用于在当前组件中访问这些属性,或者将这些属性传递给子组件。通过v-bind="$attrs"
可以将$attrs
中的属性绑定到子组件的根元素上。
以下是一个示例,演示了如何使用$attrs
属性:
<template>
<div>
<child-component v-bind="$attrs"></child-component>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
}
}
</script>
在上面的示例中,父组件通过v-bind="$attrs"
将$attrs
中的属性传递给子组件ChildComponent
。子组件可以通过props
接收这些属性,并在模板中使用。
$listeners
属性是一个对象,包含了父组件传递给当前组件的所有事件监听器。它可以用于在当前组件中绑定这些事件监听器,或者将它们传递给子组件。通过v-on="$listeners"
可以将$listeners
中的事件监听器绑定到子组件的根元素上。
以下是一个示例,演示了如何使用$listeners
属性:
vueCopy code<template>
<div>
<child-component v-on="$listeners"></child-component>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
}
}
</script>
在上面的示例中,父组件通过v-on="$listeners"
将$listeners
中的事件监听器传递给子组件ChildComponent
。子组件可以在模板中通过$emit
触发这些事件,并在父组件中监听。
需要注意的是,$attrs
和$listeners
主要用于透传属性和事件监听器,可以在需要将这些属性和事件传递给子组件的情况下使用。但是,对于具有特定含义的属性和事件,更好地使用props和自定义事件来进行传递和处理,以保持组件的清晰性和可维护性。
ref
在Vue.js中,可以使用ref
来进行组件之间的通信。ref
用于给组件或DOM元素添加一个引用,可以通过该引用来直接访问组件或DOM元素的属性和方法。
以下是一个示例,演示了如何使用ref
进行组件通信:
vueCopy code<template>
<div>
<child-component ref="child"></child-component>
<button @click="callChildMethod">调用子组件方法</button>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
methods: {
callChildMethod() {
this.$refs.child.someMethod(); // 调用子组件方法
}
}
}
</script>
在上面的示例中,父组件通过ref="child"
给子组件添加了一个引用。然后,在父组件的callChildMethod
方法中,通过this.$refs.child
访问子组件的实例,并调用了子组件的someMethod
方法。
子组件的定义如下:
vueCopy code<template>
<div>
<p>子组件内容</p>
</div>
</template>
<script>
export default {
methods: {
someMethod() {
console.log('子组件方法被调用');
}
}
}
</script>
在子组件中,定义了一个someMethod
方法,该方法在被调用时会在控制台打印一条消息。
通过ref
引用子组件,父组件可以直接访问子组件的属性和方法,从而实现组件之间的通信。需要注意的是,ref
应该在子组件已经被渲染的情况下才能访问到子组件实例,因此通常在父组件的mounted
生命周期钩子函数或后续的生命周期函数中使用ref
。
另外,需要注意的是,ref
引用是非响应式的,这意味着如果子组件发生了更新,父组件并不会自动接收到更新后的引用。因此,需要在适当的时机更新引用,例如在父组件的钩子函数中重新赋值给ref
引用。
$root
在Vue.js中,$root
是Vue实例的根实例,也就是应用程序的根组件实例。通过$root
,可以在任何组件中访问根实例的属性和方法。
以下是一些$root
的常见用法:
- 访问根实例的数据或方法:
vueCopy code// 在组件中访问根实例的数据
this.$root.someData;
// 在组件中调用根实例的方法
this.$root.someMethod();
- 在子组件中触发根实例的事件:
vueCopy code// 子组件中触发根实例的事件
this.$root.$emit('eventName', payload);
- 在子组件中访问根实例的属性或方法:
vueCopy code// 子组件中访问根实例的数据
this.$root.someData;
// 子组件中调用根实例的方法
this.$root.someMethod();
需要注意的是,$root
的使用应该谨慎。过度依赖根实例可能导致组件之间的紧密耦合,不利于组件的复用和维护。在大型应用程序中,更推荐使用状态管理库(如Vuex)来管理共享数据和实现组件间的通信,以提供更好的可维护性和可测试性。
eventbus
在Vue.js中,Event Bus(事件总线)是一种用于在组件之间进行通信的模式。它允许组件之间通过事件的方式进行解耦的消息传递。
创建一个简单的Event Bus,可以使用Vue实例作为中央事件总线:
javascriptCopy code// EventBus.js
import Vue from 'vue';
export const EventBus = new Vue();
在上面的代码中,我们创建了一个新的Vue实例EventBus
作为事件总线。
现在,我们可以在任何组件中通过Event Bus来发送和接收事件。
vueCopy code// ComponentA.vue
<template>
<div>
<button @click="sendMessage">发送消息</button>
</div>
</template>
<script>
import { EventBus } from './EventBus.js';
export default {
methods: {
sendMessage() {
EventBus.$emit('message', 'Hello from Component A!');
}
}
}
</script>
在ComponentA.vue
中,我们通过Event Bus的$emit
方法发送一个名为message
的事件,并传递了消息内容。
vueCopy code// ComponentB.vue
<template>
<div>
<p>{{ message }}</p>
</div>
</template>
<script>
import { EventBus } from './EventBus.js';
export default {
data() {
return {
message: ''
}
},
created() {
EventBus.$on('message', (payload) => {
this.message = payload;
});
}
}
</script>
在ComponentB.vue
中,我们通过Event Bus的$on
方法监听名为message
的事件,并在回调函数中更新组件的message
数据。
通过使用Event Bus,ComponentA
可以发送消息,而ComponentB
可以监听并接收该消息,实现了组件之间的解耦通信。
需要注意的是,Event Bus可以用于简单的组件通信,但在大型应用程序中,过多地依赖Event Bus可能导致事件的管理和追踪变得困难。对于更复杂的组件通信和共享状态管理,建议使用Vuex或其他状态管理库。
provide+inject
在Vue.js中,provide
和inject
是一对用于在父组件向子组件传递数据的特殊选项。
provide
选项允许你在父组件中定义要传递给后代组件的数据。它可以是一个对象或一个函数。这些被提供的数据可以通过inject
选项在子组件中访问。
下面是provide
和inject
的使用示例:
vueCopy code// 父组件
<template>
<div>
<child-component></child-component>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
provide: {
message: 'Hello from parent component',
count: 10
}
}
</script>
在上述示例中,父组件使用provide
选项来提供message
和count
两个数据给子组件。现在我们可以在子组件中使用inject
选项来接收这些数据:
vueCopy code// 子组件
<template>
<div>
<p>{{ injectedMessage }}</p>
<p>{{ injectedCount }}</p>
</div>
</template>
<script>
export default {
inject: ['message', 'count'],
computed: {
injectedMessage() {
return this.message;
},
injectedCount() {
return this.count;
}
}
}
</script>
在子组件中,我们使用inject
选项来指定要注入的数据属性,这里是message
和count
。然后可以通过这些注入的属性在子组件的模板或计算属性中访问它们。
需要注意的是,inject
选项可以接受一个数组或一个对象。如果传递一个数组,数组的元素是要注入的属性名;如果传递一个对象,对象的键是要注入的属性名,而对象的值是在子组件中使用的本地名称。在上述示例中,我们使用了数组形式。
另外,provide
和inject
并不是响应式的,也就是说当提供的值发生变化时,子组件不会自动更新。如果你希望数据能够响应式地在子组件中更新,可以考虑使用Vuex或其他状态管理方案。