Vue2是一款流行的JavaScript框架,其组件系统允许开发人员将复杂的用户界面拆分成小的、可重用的组件。在这篇文章中,我将重点介绍Vue2组件通信的各种方法。
父子组件通信
Vue2中,父组件可以向子组件传递数据和事件。通过props选项,父组件可以将数据传递给子组件。子组件可以使用这些props来渲染自身的模板或执行其他操作。
<template>
<child-component :message="parentMessage"></child-component>
</template>
<script>
export default {
data() {
return {
parentMessage: 'Hello from parent'
}
}
}
</script>
// 子组件
<template>
<div>{{ message }}</div>
</template>
<script>
export default {
props: ['message']
}
</script>
此外,子组件可以向父组件发送事件,以便父组件可以对这些事件作出响应。子组件可以使用$emit方法来触发一个自定义事件。
<template>
<button @click="sendData">Send Data</button>
</template>
<script>
export default {
methods: {
sendData() {
this.$emit('dataSent', 'Some data')
}
}
}
</script>
// 父组件
<template>
<child-component @dataSent="handleData"></child-component>
</template>
<script>
export default {
methods: {
handleData(data) {
console.log(data) // 'Some data'
}
}
}
</script>
兄弟组件通信
在Vue2中,兄弟组件之间的通信可以通过共同的父组件来实现。具体来说,兄弟组件可以使用emit和on方法来发送和接收事件。当一个兄弟组件触发事件时,它会将事件发送给共同的父组件。父组件可以数据转发给其他兄弟组件。
第一种方法:
<template>
<div>
<sibling-component-a @dataSent="handleData"></sibling-component-a>
<sibling-component-b :message="message"></sibling-component-b>
</div>
</template>
<script>
export default {
data() {
return {
message: ''
}
},
methods: {
handleData(data) {
this.message = data
}
}
}
</script>
// 兄弟组件A
<template>
<button @click="sendData">Send Data</button>
</template>
<script>
export default {
methods: {
sendData() {
this.$emit('dataSent', 'Some data')
}
}
}
</script>
// 兄弟组件B
<template>
<div>{{ message }}</div>
</template>
<script>
export default {
props: ['message']
}
</script>
第二种方法:
// main.js
Vue.prototype.$bus = new Vue() // 共享bus
// 兄弟组件A
<template>
<button @click="sendData">Send Data</button>
</template>
script>
export default {
methods: {
sendData() {
this.$bus.$emit('dataSent', 'Some data')
}
}
}
</script>
// 兄弟组件B
<template>
<div>{{ message }}</div>
</template>
<script>
export default {
data() {
return {
message: ''
}
},
mounted(){
this.$bus.$on('dataSent', (msg) => {
this.message = msg
})
},
beforeDistory(){
this.$bus.$off('dataSent')
}
}
</script>
Vuex
Vuex是Vue.js的状态管理库,它提供了一个集中式的存储来管理应用程序的状态,让组件以一种可预测和组织良好的方式访问和更新状态。Vuex存储由几个组件组成:state、mutations、actions和getters。其中,state是存储应用程序状态的对象,mutations是用于更改状态的函数,actions是用于处理异步操作的函数,getters是用于从存储中获取状态的函数。通过使用Vuex,开发人员可以更轻松地管理应用程序的状态,并使组件之间的通信更加简单和清晰。
假设有一个简单的Vue.js应用程序,其中有一个计数器组件和一个显示计数器值的组件。这两个组件都需要访问和更新同一个计数器值,我们可以使用Vuex来管理该值的状态。
首先,在应用程序中安装Vuex,然后创建一个Vuex store。store由state、mutations、actions和getters组成。在这个例子中,我们只需要一个state和一个mutation。
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
counter: 0
},
mutations: {
increment (state) {
state.counter++
}
}
})
export default store
在上面的代码中,我们创建了一个名为store的新的Vuex存储,并定义了一个名为counter的状态属性和一个名为increment的mutation函数,用于将计数器值加1。
接下来,在计数器组件中,我们可以通过调用increment mutation来更新计数器值。
<template>
<div>
<p>计数器组件</p>
<button @click="incrementCounter">增加计数器</button>
</div>
</template>
<script>
export default {
methods: {
incrementCounter () {
this.$store.commit('increment')
}
}
}
</script>
在上面的代码中,我们定义了一个名为incrementCounter的方法,该方法调用了increment mutation。
最后,在显示计数器值的组件中,我们可以使用getters来获取计数器的值。
<template>
<div>
<p>显示计数器值的组件</p>
<p>计数器值为:{{ counter }}</p>
</div>
</template>
<script>
export default {
computed: {
counter () {
return this.$store.state.counter
}
}
}
</script>
在上面的代码中,我们定义了一个名为counter的计算属性,该属性使用$store.state.counter来获取计数器的值。
通过使用Vuex,我们可以轻松地管理应用程序的状态,并确保组件之间的通信更加简单和清晰。
provide和inject
在Vue2中,提供了一种高级的组件通信方式,即provide和inject。使用provide和inject可以让你在组件树中任何位置访问一个共享的对象。
在父组件中,你可以使用provide选项来提供一个对象,该对象可以被任何后代组件使用。在后代组件中,你可以使用inject选项来注入这个对象。
<template>
<parent-component>
<child-component></child-component>
</parent-component>
</template>
<script>
export default {
provide: {
sharedData: 'Hello from ancestor'
}
}
</script>
// 父组件
<template>
<div>
<slot></slot>
</div>
</template>
// 子组件
<template>
<div>{{ sharedData }}</div>
</template>
<script>
export default {
inject: ['sharedData']
}
</script>
需要注意的是,provide和inject绑定并不是可响应的,如果想传递响应式的数据,可以这样写
// parent.vue
data () {
tableData: {
list: []
}
},
provide () {
return {
tableData: this.tableData
}
},
methods:{
getTableData(){
axios.get("url")
.then((res) => {
this.tableData.list = res.data.tableData;
console.log("我是爷组件:", this.tableData.list);
});
},
}
// child.vue
...
inject: ['taleData']
...
<el-table :data="tableData.list">
attrs和listeners
在Vue2中,每个组件实例都会有一些特殊的属性和方法,可以用来访问组件的属性、事件、插槽等信息。其中,attrs和listeners是两个非常有用的属性。
attrs是一个对象,包含了传递给组件的非prop属性。你可以在组件的模板中使用v-bind="$attrs"来将这些属性传递给子组件。
<template>
<child-component message="Hello" data-foo="bar" @update="updateFn" v-on="$listeners"></child-component>
</template>
// 子组件
<template>
<div>{{ message }}</div>
<div>{{ $attrs }} // { data-foo: bar }
<button @click="clickFn">click me</button>
</template>
<script>
export default {
props: ['message'],
methods: {
clickFn(){
console.log(this.$listeners) // { update: ƒ invoker() }
}
}
}
</script>
ref
在Vue2中,ref属性允许你访问组件的DOM元素或子组件实例。你可以通过在模板中使用ref属性来为组件或DOM元素指定一个引用名。然后,你可以通过$refs来访问这些引用。
<template>
<child-component ref="child"></child-component>
</template>
// 子组件
<template>
<div>Child Component</div>
</template>
<script>
export default {
mounted() {
console.log(this.$refs.child) // 子组件实例
}
}
</script>
$parent
在Vue.js中,每个组件都有一个$parent属性,它指向该组件的父组件。可以通过$parent属性访问父组件的属性或方法,从而实现父子组件之间的通信。
例如,如果一个子组件需要在父组件中触发一个事件,可以使用emit()方法。假设父组件有一个名为“handleEvent”的方法:
// 父组件
<template>
<div>
<child-component></child-component>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue'
export default {
methods: {
handleEvent() {
console.log('Event handled in parent component')
}
},
components: {
ChildComponent
}
}
</script>
子组件可以通过$parent访问父组件的handleEvent方法,从而触发事件:
// 子组件
<template>
<button @click="$parent.handleEvent()">Trigger Parent Event</button>
</template>
在Vue2中,parent属性允许你访问父组件实例。但是,建议尽量避免使用$parent,因为它会让你的组件与其它组件的层次结构紧密耦合,使组件变得不够灵活。
$children
在Vue.js中,$children是一个组件的直接子组件数组,是一个Vue实例的属性。可以通过访问这个属性来访问和操作组件的子组件。
需要注意的是,$children是一个动态属性,它的值会随着组件的渲染和销毁而改变。此外,使用children访问子组件时,需要注意子组件的顺序和数量,因为Vue.js不保证$children数组中子组件的顺序和组件树中的顺序相同。
下面是一个使用$children属性访问子组件的简单示例:
<template>
<div>
<button @click="onButtonClick">Click me</button>
<child-component></child-component>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
methods: {
onButtonClick() {
// 访问子组件
const childComponent = this.$children[0];
// 调用子组件的方法
childComponent.doSomething();
}
}
};
</script>
总结:
常见使用场景可以分为三类:
- 父子组件通信: props/emit、parent/children、 provide/inject、ref、attrs/listeners
- 兄弟组件通信: eventBus、 vuex
- 跨级通信: eventBus、 vuex、 provide/inject、attrs/listeners