Vue组件间通信
1、Props和Events(主要用于父子组件间通讯)
该类通讯方式基础知识介绍
Props(父传子)
props
是 Vue.js 中组件间通信的一种方式,允许父组件向其子组件传递数据。
在父组件中,你可以使用 props
关键字将数据传递到子组件中。例如:
<template>
<child-component :my-prop="message"></child-component>
</template>
<script>
export default {
data () {
return {
message: 'Hello Vue.js!'
}
}
}
</script>
在子组件中,你可以在其 props
选项中声明接收的属性。例如:
<template>
<p>{{ myProp }}</p>
</template>
<script>
export default {
props: ['myProp']
}
</script>
需要注意的是,子组件中的 props
数据是不可修改的。如果需要对数据进行修改,可以将数据复制到本地数据中,再在本地数据中进行修改。
Events(子传父)
$emit
Vue.js 中的 events 是父子组件之间通信的重要方式。events 允许父组件监听并响应来自子组件的事件。
$emit
是 Vue.js 的一个实例方法,用于向父组件传递事件。
当在子组件内部调用 $emit
方法时,可以将事件向上冒泡,从而触发父组件中的事件处理函数。
使用方法如下:
this.$emit('eventName', arg1, arg2, ...)
第一个参数 eventName
表示事件名称,可以自定义。后面的参数是传递给父组件的参数。
在父组件中,可以通过 on 指令监听该事件,并编写事件处理函数
通讯
使用方法:
- 父组件监听事件:使用 v-on 指令监听子组件触发的事件。
<template>
<child-component @myEvent="handleEvent"></child-component>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent,
},
methods: {
handleEvent(data) {
console.log(data);
},
},
};
</script>
子组件中触发事件:使用 this.$emit
函数触发事件,并传递数据。
<template>
<div>
<button @click="handleClick">Click me</button>
</div>
</template>
<script>
export default {
methods: {
handleClick() {
this.$emit('myEvent', 'Hello World');
},
},
};
</script>
通讯
Props主要用于父组件向子组件传递数据,Events则是用于子组件向父组件传递数据。下面是一个简单的示例代码,演示了如何使用Props和Events实现组件间的通讯:
父组件:
<template>
<div>
//:message为props,其中的内容递送给子组件
//@child—event为event,其中的方法用来处理子组件发来的数据
<child-component :message="parentMessage" @child-event="handleChildEvent"/>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
name: 'ParentComponent',
components: {
ChildComponent,
},
data() {
return {
parentMessage: 'Hello from parent component!',
};
},
methods: {
handleChildEvent(childMessage) {
console.log(`Received message from child component: ${childMessage}`);
},
},
};
</script>
子组件:
<template>
<div>
<p>{{ message }}</p>
<button @click="sendEvent">Send Event</button>
</div>
</template>
<script>
export default {
name: 'ChildComponent',
//此数据从父组件获得
props: {
message: String,
},
methods: {
sendEvent() {
const childMessage = 'Hello from child component!';
this.$emit('child-event', childMessage);
},
},
};
</script>
在上面的示例代码中,父组件向子组件传递数据使用了Props,子组件通过props选项接收了来自父组件的message数据,并将其显示在了页面上。父组件通过v-bind指令将parentMessage数据绑定到了子组件的message props上。
在子组件向父组件传递数据方面,使用了Events。子组件在sendEvent方法中创建了一个包含子组件发送的消息的字符串,并通过this.$emit()方法触发了名为’child-event’的自定义事件。父组件则在模板中使用@child-event监听了这个事件,并在handleChildEvent方法中接收并处理了子组件发送的消息。
2、$emit 和 $on
// ChildA.vue
<template>
<div>
<button @click="emitData">发送数据到ChildB组件</button>
</div>
</template>
<script>
export default {
methods: {
emitData() {
this.$emit('passData', 'hello from ChildA');
},
},
};
</script>
// ChildB.vue
<template>
<div>
<p>接收到的数据:{{ data }}</p>
</div>
</template>
<script>
export default {
data() {
return {
data: '',
};
},
mounted() {
//对passData数据结构进行监听,当监听道passData变化时,调用receiveData
this.$on('passData', this.receiveData);
},
methods: {
receiveData(data) {
this.data = data;
},
},
beforeDestroy() {
this.$off('passData', this.receiveData);
},
};
</script>
在这个例子中,ChildA
组件定义了一个 emitData
方法,并在点击按钮时触发 $emit('passData', 'hello from ChildA')
,其中第一个参数 'passData'
是事件名称,第二个参数 'hello from ChildA'
是要传递的数据。
ChildB
组件中在 mounted
钩子中使用 $on
方法监听事件 'passData'
,并在事件触发时执行 receiveData
方法,将接收到的数据保存在 data
中。在 beforeDestroy
钩子中使用 $off
方法移除监听器,以避免内存泄漏。
这种方式通过 $emit
和 $on
方法实现了父组件向子组件传递数据的功能,也可以通过将 $emit
改为在子组件上触发事件来实现子组件向父组件传递数据。
3、$refs
$refs简介
Vue 中的 $refs 是一个 Vue 实例的属性,它可以用来访问模板中的 DOM 元素,组件,或某些子组件。
$refs 不是响应式数据,不能直接在模板中使用,仅可以在 JavaScript 代码中使用。
使用 $refs 的方法是在某个 DOM 元素或组件上加上 ref 属性,并将其作为 $refs 的一个属性来访问,代码示例如下:
HTML:
<template>
<div>
<input type="text" ref="inputRef">
<button @click="sayHello">Click Me</button>
</div>
</template>
JavaScript:
<script>
export default {
methods: {
sayHello() {
console.log(this.$refs.inputRef.value)
}
}
}
</script>
在上面的代码中,我们为输入框添加了 ref 属性,并在点击按钮时使用 $refs 访问该输入框的值。
总的来说,$refs 可以帮助我们访问模板中的某些特定元素,但是应该尽量少用,因为它不是响应式的,并且它的使用有可能导致代码变得不可维护。因此,对于大多数情况,应该使用响应式数据和计算属性。
通讯
可以通过$refs属性访问子组件的实例,从而直接调用子组件的方法或访问子组件的数据。下面是一个简单的示例:
父组件:
<template>
<div>
<child-component ref="child"></child-component>
<button @click="callChildMethod">Call Child Method</button>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
methods: {
callChildMethod() {
// 通过 $refs 访问子组件的方法
this.$refs.child.childMethod();
}
}
}
</script>
子组件:
<template>
<div>
<p>{{ message }}</p>
</div>
</template>
<script>
export default {
data() {
return {
message: 'Hello from Child Component'
}
},
methods: {
childMethod() {
console.log('This is a method in child component');
}
}
}
</script>
4、Vuex方式
Vue组件间通信的Vuex方式是通过Vuex状态管理库来实现的。它允许我们在一个单独的地方维护应用程序的状态,并在所有组件中共享这个状态。以下是一个简单的示例,展示了如何在两个组件之间使用Vuex进行通信:
1、首先,在src目录下新建一个store.js文件,用来创建Vuex store。
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
//state:存储应用程序的状态,通常是一个对象。
state: {
message: ''
},
//mutations:修改state的唯一途径,它们是同步的事务。
mutations: {
setMessage(state, payload) {
state.message = payload
}
},
//actions:提交mutations,但是可以包含任意异步操作。
actions: {
setMessage(context, payload) {
context.commit('setMessage', payload)
}
},
//getters:对state进行派生,通常是一些计算属性。
getters: {
getMessage(state) {
return state.message
}
}
})
2、在需要使用Vuex的组件中引入store。
import store from '@/store'
3、在发送组件中触发Vuex中的action,以更新state中的值。
<template>
<div>
<input type="text" v-model="message">
<button @click="setMessage">Send</button>
</div>
</template>
<script>
export default {
data() {
return {
message: ''
}
},
methods: {
setMessage() {
this.$store.dispatch('setMessage', this.message)
}
}
}
</script>
4、在接收组件中通过计算属性获取Vuex中的值。
<template>
<div>
<p>Received message: {{ message }}</p>
</div>
</template>
<script>
export default {
computed: {
message() {
return this.$store.getters.getMessage
}
}
}
</script>
在这个示例中,我们创建了一个名为message的状态属性,并定义了一个名为setMessage的mutation来更新该属性的值。我们还定义了一个名为setMessage的action来提交mutation,以便我们可以从发送组件中调用它。
在发送组件中,我们将message的值绑定到一个文本输入框,并创建一个名为setMessage的方法,该方法将使用dispatch方法触发Vuex action来更新状态值。
在接收组件中,我们使用计算属性来获取Vuex中的值,以便我们可以在模板中显示它。
5、Bus(事件总线)方式
使用Vue实例作为事件总线,组件之间通过事件总线进行通信。
<template>
<div>
<p>{{ message }}</p>
<button @click="sendMessage">发送消息</button>
</div>
</template>
<script>
export default {
data() {
return {
message: ''
}
},
methods: {
sendMessage() {
// 向事件总线发送消息
this.$bus.$emit('message', 'Hello World!');
}
},
created() {
// 监听事件总线的消息
this.$bus.$on('message', (message) => {
this.message = message;
});
}
}
</script>
在上面的示例中,我们创建了一个名为 $bus
的新的Vue实例,并通过 $emit
方法向事件总线发送消息,在组件的 created
钩子中通过 $on
方法监听事件总线的消息,并将接收到的消息保存到组件的 message
变量中。
当需要在另一个组件中接收这个消息时,也可以使用 $bus.$on
方法监听同样的事件名,并在回调函数中处理接收到的消息。
需要注意的是,当使用Bus方式实现组件间通信时,需要手动销毁事件总线。可以在组件的 beforeDestroy
钩子中使用 $bus.$off
方法移除事件监听,以避免内存泄漏。
6、Provide 和 Inject
Provide
和 Inject
是 Vue 提供的一种高级组件间通讯方式,它可以让祖先组件向后代组件注入一个依赖,使得子孙组件可以访问到这个依赖。
使用 Provide
和 Inject
时,我们需要在父组件中通过 provide
方法提供一个值,然后在子组件中通过 inject
方法注入这个值。这个值可以是任何 JavaScript 数据类型,例如对象、数组、字符串等。
<template>
<div>
<p>父组件数据:{{data}}</p>
<child-component></child-component>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent,
},
data() {
return {
data: '这是父组件的数据',
};
},
provide() {
// 将数据注入provide对象中
return {
data: this.data,
};
},
};
</script>
<template>
<div>
<p>子组件数据:{{data}}</p>
</div>
</template>
<script>
export default {
inject: ['data'], // 注入父组件provide对象中的数据
data() {
return {
data: '',
};
},
created() {
// 使用注入的数据
this.data = this.data || '这是子组件的默认数据';
},
};
</script>
在这个例子中,父组件中的provide
选项将数据注入了provide对象中,而子组件中使用inject
选项来注入provide对象中的数据,实现了父子组件之间的通信。
需要注意的是,provide
和inject
并不是响应式的,所以需要手动触发组件更新来重新渲染页面。同时,在使用inject
时需要注意默认值的处理,否则可能会导致数据未正常显示的问题。
Provide 和 Inject 的优点:
- 方便数据共享。使用 Provide 和 Inject,可以方便的共享数据。
- 不依赖于父子关系。使用 Provide 和 Inject,可以在任意组件间共享数据,不仅限于父子关系。
- 可以保证数据的响应式。在 Provide 中定义的数据是响应式的,并且可以在子组件中直接使用。