视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
Vue组件通信的几种实现方法
2020-11-27 21:58:03 责编:小采
文档

组件的通信

一般常见的组件之间的通信有以下几种情况,A和B,B和C,B和D之间都是父子关系,C和D之间是兄弟组件关系。

常用的通信手段有两种:

1.ref:给元素或组件注册引用信息

2.children:访问父级组件和子组件的实例。

这两种方式都是直接通过实例的方式获取的方式。示例如下:

//comA组件A
export default {
 data () {
 return {
 title: '测试通信'
 }
 },
 methods: {
 sayHello () {
 window.alert('你好');
 }
 }
}

这里引用组件A

<template>
 <comA ref="comA"></comA>
</template>
<script>
 export default {
 mounted () {
 const comA = this.$refs.comA;
 console.log(comA.title); // 测试通信
 comA.sayHello(); // 调用组件comA的方法
 }
 }
</script>

上面的例子我们可以看出我们使用ref来获取组件的实例上的方法和数据

<div id="count">
 <button @click="showmsg">
 显示两个组件的信息
 </button>
 <child1></child1>
 <child2></child2>
 </div>
<template id="child1">
 <div>
 {{ msg }}
 </div>
</template>
<template id="child2">
 <div>
 {{ msg }}
 </div>
</template>
<script>
 Vue.component('child1', {
 template: '#child1',
 data () {
 return {
 msg: '这是子组件1的信息'
 }
 }
 })
 Vue.component('child2', {
 template: '#child2',
 data () {
 return {
 msg: '这是子组件2的信息'
 }
 }
 })
 new Vue({
 el: '#count',
 data: {
 
 },
 methods: {
 showmsg () {
 for(var i = 0; i < this.$children.length; i++) {
 alert(this.$children[i].msg)
 }
 }
 }
 })
</script>

$children 返回所有子组件的实例,是一个数组

<div id="count">
 父组件中的msg: {{ msg }}
 <child1 ref='c1'></child1>
 <child2 ref='c2'></child2>
 </div>
<template id="child1">
 <div>
 {{ msg }}
 <button @click="showpmsg">
 显示父组件msg
 </button>
 </div>
</template>
<template id="child2">
 <div>
 {{ msg }}
 </div>
</template>
<script>
 Vue.component('child1', {
 template: '#child1',
 data () {
 return {
 msg: '这是子组件1的信息'
 }
 },
 methods: {
 showpmsg () {
 alert(this.$parent.msg)
 }
 }
 })
 Vue.component('child2', {
 template: '#child2',
 data () {
 return {
 msg: '这是子组件2的信息'
 }
 }
 })
 new Vue({
 el: '#count',
 data: {
 msg: 'hello parent'
 }
 })
</script>

这两种方式是基于组件的上下文环境访问到父组件或者全部子组件(数组)。这种方式有很大的弊端是,无法跨级或兄弟间进行通信,比如如下的结构

// parent.vue
<component-a></component-a>
<component-b></component-b>
<component-c></component-c>

我们假如想在组件A中获取其他组件那么我们可能需要使用vuex或者和Bus事件总线的方式进行解决。

事件总线

定义事件总线的方式有以下两种

// bus.js 事件总线

import Vue from 'vue'
export const $bus = new Vue()

// main.js我们再main入口中定义这个事件总线
Vue.prototype.$bus = new Vue()

发送事件

对下面comA说明,会接收来自父组件的参数number,并显示出来;有个按钮,点击会调用函数handleAddRandom,生成一个随机数,并调用事件总线的$emit方法,将随机数给事件总线,由事件总线进行数据传递。

<template>
 <div>
 {{number}}
 <button @click="handleAddRandom">随机增加</button>
 </div>
</template>

<script>
import $bus from ../bus.js
 export default {
 name: "counter",
 props: {
 number: {
 type: Number
 }
 },
 methods: {
 handleAddRandom() {
 const num = Math.floor(Math.random() * 100 + 1);
 console.log("生产的num:" + num);
 this.$bus.$emit('add', num);
 }
 }
 }
</script>

接收事件

<template>
 <div>
 随机增加:
 <counter :number="number"></counter>
 </div>
</template>

<script>
 import counter from './counter'

 export default {
 name: "index",
 components: {
 counter
 },
 data() {
 return {
 number: 0
 }
 },
 methods: {
 handleAddRandom(num) {
 this.number += num;
 }
 },
 created() {
 //this.$bus.$on需要在created中使用,否则不会生效
 this.$bus.$on('add', this.handleAddRandom);
 },
 beforeDestroy() {
 //需要在beforeDestroy中移除
 this.$bus.$off('add', this.handleAddRandom);
 }
 }
</script>

<style scoped>

</style>

上面是我们通过事件总线的方式进行通信

然后我们来说下另一种可以媲美Vuex的一种方式provide / inject

provide / inject

说起这两个API可能大家不太明白我们来举例子说明

// A组件
export default {
 provide: {
 name: 'Aresn'
 }
}

// B组件
export default {
 inject: ['name'],
 mounted () {
 console.log(this.name); // Aresn
 }
}

代码中我们可以看到我们再组件A中设置了一个provide:{name:"Aresn"},这个方法的作用就是将该变量提供给所有的子组件。我们在B组件中我们使用indect获取了这个变量,这样我们就可以使用this.name获取到这个那么变量。下面我们可以使用一些骚操作大胆的替代Vuex。(这里说明一下官网中不建议我们是使用这两个API在常规应用程序中,建议使用在高阶组件中,建议归建议用的好就可以啦)

使用provide / inject期待Vuex

<template>
 <div>
 <router-view></router-view>
 </div>
</template>
<script>
 export default {

 }
</script>
Vue cli中搭建出来的项目结构中都会有一个app.vue作为入口组件,我们可以使用这个API在上面大做文章。
<script>
 export default {
 provide () {
 return {
 app: this
 }
 },
 data () {
 return {
 userInfo: null
 }
 },
 methods: {
 getUserInfo () {
 // 这里通过 ajax 获取用户信息后,赋值给 this.userInfo,以下为伪代码
 $.ajax('/user/info', (data) => {
 this.userInfo = data;
 });
 }
 },
 mounted () {
 this.getUserInfo();
 }
 }
</script>

这里我们把根组件实例作为一个参数传递给app变量,下面我们就可以通过app[变量||方法]达到vuex的目的

<template>
 <div>
 {{ app.userInfo }}
 </div>
</template>
<script>
 export default {
 inject: ['app'],
 methods: {
 changeUserInfo () {
 // 这里修改完用户数据后,通知 app.vue 更新,以下为伪代码
 $.ajax('/user/update', () => {
 // 直接通过 this.app 就可以调用 app.vue 里的方法
 this.app.getUserInfo();
 })
 }
 }
 }
</script>

但是这样做有一个弊端那就是可能会让根组件app.vue的代码变得特别的臃肿,当然也有解决办法,我们可以使用mixins混合的方式将不同的逻辑分开写到不同的js里面然后通过 mixins: [mixins_user]的方式在app.vue中引用这个mixin。

下载本文
显示全文
专题