vue---组件通讯

Posted czheng7

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue---组件通讯相关的知识,希望对你有一定的参考价值。

 Vue的通信方式有几种?隔代组件的通信用哪种方式解决?

 

一:props/$emit

父传子:

 

// parent.vue
<s-child v-bind:infos="informations" /> // infos对应子组件上 data() { return { informations: [ { name: "A1", age: 16 }, { name: "A2", age: 17 }, { name: "A3", age: 18 }, { name: "A4", age: 19 }, ] } }

// child.vue
// 子组件props接收,

...

props: ["infos"]    // 接收父组件传递的参数 infos   一般不用[]接收 
...

子传父 $emit

// 父组件
<s-child v-on:infos="cy" />     与子组件infos事件保持一致
<div>{{msg}}</div>


data() {
    msg: ‘‘
}


methods: {
    cy(somedata) {
        this.msg =  somedata
    }
}


// 子组件
<button v-on:click="onClick">向父组件传参</button>


data() {
    return {
        childmsg: "我是子组件的值"
    }
}
methods: {
    onClick: function () {
        this.$emit(‘infos‘, this.childmsg)  // infos是父组件绑定的事件,this.childmsg作为参数传过去
    }
}

 二:$children/$parent

// parent
<template>
    <div>
        <div>
            <div>{{ msg }}</div>
            <s-child></s-child>
            <button @click="changeA">点击改变子组件值</button>
        </div>
    </div>
</template>
<script>
    import Child from ‘./child‘
    export default {
        name: ‘ThisParent‘,
        data() {
            return {
                // message: ‘hello‘
                msg: ‘Welcome parents‘
            }
        },
        components: {
            "s-child": Child
        },
        methods: {
            changeA() {
                // 获取到子组件A
                this.$children[0].messageA = ‘this is new value for parents‘
            }
        }
    }
</script>
// child
<template>
    <div>
        <div class="com_a">
            <span>{{ messageA }}</span>
            <p>获取父组件的值为:{{ parentVal }}</p>
        </div>
    </div>
</template>
<script>
    export default {
        data() {
            return {
                messageA: ‘this is old‘
            }
        },
        computed:{
            parentVal() {
                return this.$parent.msg;
            }
        }
    }
</script>
    要注意边界情况,如在#app上拿$parent得到的是new Vue()的实例,在这实例上再拿$parent得到的是undefined,而在最底层的子组件拿$children是个空数组。也要注意得到$parent和$children的值不一样,$children 的值是数组,而$parent是个对象
    上面两种方式用于父子组件之间的通信, 而使用props进行父子组件通信更加普遍; 二者皆不能用于非父子组件之间的通信。

 三:provide/inject

概念: provide/ injectvue2.2.0新增的api, 简单来说就是父组件中通过provide来提供变量, 然后再子组件中通过inject来注入变量。注意: 这里不论子组件嵌套有多深, 只要调用了inject 那么就可以注入provide中的数据,而不局限于只能从当前父组件的props属性中回去数据

假设拥有三个组件: A.vue, B.vue, C.vue 其中C是B的子组件,B是A的子组件
// A.vue
<template>
    <div>
        <com-b></com-b>
    </div>
</template>

<script>
    import comB from ‘./B‘
    export default {
        name: ‘A‘,
        provide: {
            for: "A里面的值"
        },
        components: {
            comB
        }
    }
</script>
// B.vue
<template>
    <div>
        {{demo}}
        <com-c></com-c>
    </div>
</template>

<script>
    import comC from ‘./C‘
    export default {
        name: ‘B‘,
        inject: [‘for‘],
        data() {
            return {
                demo: this.for
            }
        },
        components: {
            comC
        }
    }
</script>
// C.vue
<template>
    <div>
        {{demo}}
    </div>
</template>

<script>
    export default {
        name: ‘C‘,
        inject: [‘for‘],
        data() {
            return {
                demo: this.for
            }
        }
    }
</script>

# 四:ref/$refs

父组件如何直接调取子组件的数据和方法,而不是通过子组件传上来的.我们要理解父组件直接拿事件是在父组件上,子组件传上来数据,事件是在子组件上,是完全不同的两种情况

ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例,可以通过实例直接调用组件的方法或访问数据, 我们看一个ref 来访问组件的例子:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
    <div id="app-7">
        <div>
            <to-child ref=‘ch‘></to-child>
            <h1 @click="onclick">我是父组件点击获取子组件信息</h1>
        </div>
    </div>
</body>

<script>

Vue.component(‘to-child‘, {
  template: ‘<div>我是子组件</div>‘,
  data() {
            return {
                sonData: ‘我是子组件的数据‘
            }
        },
        methods: {
            sonMethod() {
                console.log(‘我是子组件的方法sonMethod‘)
            }
        }
})

var app7 = new Vue({
  el: ‘#app-7‘,
  data() {
            return { }
        },
        methods: {
            onclick() {
                // 父组件可以通过$refs拿到子组件的对象
                // 然后直接调用子组件里面methods方法和data数据
                let chil = this.$refs.ch

                console.log(chil)   // 子组件对象
                console.log(chil.sonData)       // 子组件数据
                console.log(chil.sonMethod())     // 子组件的方法
            }
        }
})
</script>

</html>

# 五:eventBus

EventBus又称为事件总线。在Vue中可以使用EventBus来作为组件传递数据的桥梁,就像是所有组件共用相同的事件中心,可以向该中心注册发送或者接收事件,所以组件都可以上下平行通知其它组件。但如果使用不慎,就会造成维护灾难。因此推荐更加强大的Vuex作为状态管理中心,将通知概念上升到共享状态层次。

使用 EventBus

初始化:
// 第一种方式:可以在main.js 中,初始化 EventBus

Vue.prototype.$EventBus = new Vue()

// 第二种方式:创建一个Bus.js ,再创建事件总线并将其导出,以便其它模板可以使用或者监听

// Bus.js

import Vue from ‘vue‘

export const EventBus = new Vue();

// 你需要做的只是引入 Vue 并导出它的一个实例(在这种情况下,我称它为 EventBus )。
// 实质上它是一个不具备DOM的组件,它具有的仅仅只是它实例方法而已,因此它非常的轻便。

这样我们就创建了EventBus,接下来只需要在组件中加载它,并调用同一个方法。

发送和接收事件

和父子组件通信差不多,用 EventBus.$emit(‘emit事件名‘,数据) 发送, EventBus.$on("emit事件名", callback(payload1,…)) 接受

// additionNum.vue 中发送事件
<template>
    <div>
        <button v-on:click="additionHandle">+加法</button>
    </div>
</template>

<script>
    import {EventBus} from ‘./bus.js‘
    console.log(EventBus)
    export default {
        data() {
            return{
                num: 1
            }
        },
        methods: {
            additionHandle() {
                EventBus.$emit(‘addition‘, {
                    num: this.num++
                })
            }
        }
    }
</script>
// showNum.vue 中接收事件
<template>
    <div>
        <div>计算和:{{count}}</div>
    </div>
</template>

<script>
    import {EventBus} from ‘./bus.js‘

    export default {
        data() {
            return{
               count: 0
            }
        },
        mounted() {
            EventBus.$on(‘addition‘, param => {
                this.count = param.num;
            })
        }
    }
</script>

如果只需要监听(接收)一次数据可以使用 EventBus.$once(‘事件名‘, callback(payload1,...)

移除事件监听者

EventBus.$off(‘事件名‘,回调函数)

  • EventBus.$off(‘事件名‘, callback),只移除这个回调的监听器。

  • EventBus.$off(‘事件名‘),移除该事件所有的监听器。

  • EventBus.$off(), 移除所有的事件监听器,注意不需要添加任何参数。

// 导入我们刚刚创建的 EventBus
import { EventBus } from ‘../Bus.js‘

// 事件监听函数
const clickHandler = function(clickCount) {
  console.log(`Oh, hello)`)
}

// 开始监听事件
EventBus.$on(‘i-got-clicked‘, clickHandler);

// 停止监听
EventBus.$off(‘i-got-clicked‘, clickHandler);

 

# 六:Vuex

 

# 七:localStorage/sessionStorage

 

# 八:$attrs 与 $listeners

 

 

以上是关于vue---组件通讯的主要内容,如果未能解决你的问题,请参考以下文章

Vue组件通讯

vue中的组件

vscode代码片段生成vue模板

Vue_(组件通讯)简单使用父子组件

Vue2组件间通讯

VUE组件通讯