Github

抽空梳理了一下Vue罕用的组件之间的通信形式,而后想通过应用的技术进行分类整理笔记。

Prop传值

应用范畴

父组件向子组件传值。

应用办法

父组件
<template>  <div id="app">      <div class="app">          <div class="title">App.vue</div>      </div>        <!-- 将text1绑定给Component1 -->      <component1 :text="text1" />  </div></template>export default {    name: 'App',    components: {        Component1,    },    data(){        return{            text1:"Text From App.vue",        }    }}</script>
子组件
<template>    <div class="component1">        <div class="title">Component1</div>        <div>            <!-- 将父组件传递过去的text进行展现 -->            <span class="text-bold">text:</span>            {{text}}        </div>    </div></template><script>export default {    name: "Component1",    // 通过props来接管text    props:{        text:{            type:String        }    },}</script>
成果展现

留神

父组件通过Prop传值给子组件是属于单向数据流,因而当父组件批改该值的时候,子组件也会随之更新数据;而子组件是不应该在外部扭转 prop的。如果你能够这么做,然而Vue不举荐此做法,并会在控制台收回正告。

v-on事件绑定

应用范畴

子组件调用父组件办法。

应用办法

父组件
<template>  <div id="app">      <div class="app">          <div class="title">App.vue</div>          <div>              <span class="text-bold">count:</span>              {{count}}          </div>      </div>        <!-- 将事件addCount绑定给Component1 -->      <component1 @addCount="addCount" />  </div></template><script>import Component1 from "@/components/Component1";export default {    name: 'App',    components: {        Component1    },    data(){        return{            count:0        }    },    methods:{        addCount(){            this.count++;        }    }}</script>
子组件
<template>    <div class="component1">        <div class="title">Component1</div>        <!-- Component1的button触发addParentCount -->        <button @click="addParentCount">            add count of App.vue        </button>    </div></template><script>export default {    name: "Component1",    methods:{        // 调用组件绑定的addCount办法        addParentCount(){            this.$emit('addCount')        }    }}</script>
成果展现

留神

this.$emit() 的第一个参数为事件绑定的EventName,而从第二个参数开始为函数的参数,能够传多个参数值,意味着能够通过此办法从子组件传值给父组件。

ref组件注册

适用范围

父组件获取子组件的值或调用子组件的办法。

应用办法

父组件
<template>  <div id="app">      <div class="app">          <div class="title">App.vue</div>            <!-- 显示获取到的子组件的text -->          <div>              <span class="text-bold">text:</span>              {{text2}}          </div>            <!-- 减少子组件的count值 -->          <button @click="ChildrenCount">              add count of Component1.vue          </button>      </div>      <!-- 进行组件注册 -->      <component1 ref="component1" />  </div></template><script>import Component1 from "@/components/Component1";export default {    name: 'App',    components: {        Component1,    },    data(){        return{            text2:''        }    },    mounted() {        // 获取子组件的text1值        this.text2 = this.$refs.component1.text1 || '';    },    methods:{        // 调用子组件的办法        ChildrenCount(){            this.$refs.component1.addCount();        }    }}</script>
子组件
<template>    <div class="component1">        <div class="title">Component1</div>        <div>            <span class="text-bold">count:</span>            {{count}}        </div>    </div></template><script>export default {    name: "Component1",    data(){        return{            // 父组件获取到此值            text1: 'Text From Component1.vue',            count: 0        }    },    methods:{        // 父组件调用此办法        addCount(){            this.count++;        }    }}</script>
成果

留神

this.$refs 是组件渲染后才会进行填充,因而无奈在计算属性 computed 应用,打印进去会显示 undefined

EventBus事件总线

应用范畴

任意组件间的事件调用。

应用办法

初始化EventBus

共有两种形式能够初始化EventBus,第一种形式是新建一个 eventBus.js ,内容如下:

import Vue from 'vue'export const EventBus = new Vue()

而后应用时均在两个组件内引入该文件。

import { EventBus } from "../eventBus.js";

而第二种形式是全局注册EventBus。

在我的项目的 main.js 文件下,插入注册代码:

Vue.prototype.$EventBus = new Vue()

而后应用时即可通过 this.$EventBus 调用。

前面的案例均用第二种办法实现。

第一个组件
<template>    <div class="component2">        <div class="title">Component2</div>            <!-- 获取input值更新另一个组件的count值 -->        <div>            <input type="number" placeholder="Number..." v-model="value">        </div>        <!-- 点击button触发事件 -->        <button @click="changeComponent1Count">            change count of Component1        </button>    </div></template><script>export default {    name: "Component2",    data() {        return {            value:''        }    },    methods:{        // 在EventBus总线注册changeCount事件,并将value值传过来        changeComponent1Count(){            this.$EventBus.$emit("changeCount",this.value)        }    }}</script>
第二个组件
<template>    <div class="component1">        <div class="title">Component1</div>        <div>            <span class="text-bold">count:</span>            {{count}}        </div>    </div></template><script>export default {    name: "Component1",    data(){        return{            count: 0        }    },    // 在mounted中监听EventBus接管changeCount事件,并触发回调函数将value值赋给count    mounted(){        this.$EventBus.$on('changeCount',(value)=> this.count = value);    }}</script>
成果

留神

尽管在Vue中能够应用 EventBus 来作为沟通桥梁的概念,就像是所有组件共用雷同的事件核心,能够向该核心注册发送事件或接管事件,使得所有组件都能够高低平行地告诉其余组件,然而若应用不慎,就会造成难以保护的“劫难”。

Vue是单页利用,如果你在某一个页面刷新了之后,与之相干的 EventBus 会被移除,这样就导致业务走不上来。还要就是如果业务有重复操作的页面, EventBus 在监听的时候就会触发很屡次,也是一个十分大的隐患。这时候咱们就须要好好解决 EventBus 在我的项目中的关系。通常会用到,在vue页面销毁时,同时移除 EventBus 事件监听。

移除EventBus 事件监听的办法如下:

// 移除指定事件this.$EventBus.$off('changeCount')// 移除所有事件this.$EventBus.$off()

&dollar;parent与&dollar;children

应用范畴

通过插槽嵌套的父子组件进行事件调用和传值。

应用办法

App.vue
<template>  <div id="app">      <component3>          <component4></component4>      </component3>  </div></template><script>import Component3 from "@/components/Component3";import Component4 from "@/components/Component4";export default {    name: 'App',    components: {        Component3,        Component4,    }}</script>
父组件
<template>    <div class="component3">        <div class="title">Component3</div>        <!-- 获取到子组件的text1值 -->        <div>            <span class="text-bold">text:</span>            {{text2}}        </div>              <div>            <span class="text-bold">count:</span>            {{count}}        </div>        <!-- 减少子组件的count值 -->        <button @click="addChildrenCount">            add count of Component4.vue        </button>              <!-- 插槽 -->        <slot></slot>    </div></template><script>export default {    name: "Component3",    data() {        return {            text1: 'Text From Component3.vue',            text2:'',            count: 0        }    },    mounted() {        // 获取子组件的text1值        this.text2 = this.$children[0].text1;        // 监听子组件调用changeCount,并将参数value赋值给父组件的count        this.$on("changeCount",value => this.count = value);    },    methods:{        addChildrenCount(){            // 调用第一个子组件绑定的addCount办法            this.$children[0].$emit('addCount');        }    }}</script>
子组件
<template>    <div class="component4">        <div class="title">Component4</div>        <!-- 获取到父组件的text1值 -->        <div>            <span class="text-bold">text:</span>            {{text2}}        </div>              <div>            <span class="text-bold">count:</span>            {{count}}        </div>              <div>            <input type="number" placeholder="Number..." v-model="value">        </div>        <!-- 批改父组件的count值 -->        <button @click="changeParentCount">            change count of Component3.vue        </button>    </div></template><script>export default {    name: "Component4",    data() {        return {            text1: 'Text From Component4.vue',            text2:'',            count: 0,            value:''        }    },    mounted() {        // 获取父组件的text1值        this.text2 = this.$parent.text1;        // 监听父组件调用addCount,并将count++        this.$on('addCount',() => this.count++);    },    methods:{        changeParentCount(){            // 调用父组件绑定的changeCount办法,并传入value参数            this.$parent.$emit('changeCount',this.value)        },    }}</script>
成果

留神

$refs$parent$children 是组件渲染后才会进行填充,因而无奈在计算属性 computed 应用。

$children 返回的是一个数组,一个父组件可能有多个子组件,但一个子组件只能有一个父组件。

provide与inject

应用范畴

父组件向任一后辈组件传值和办法,实用于失常嵌套和插槽嵌套。

应用办法

App.vue
<template>  <div id="app">      <component3>          <component4>              <component5></component5>          </component4>      </component3>  </div></template><script>import Component3 from "@/components/Component3";import Component4 from "@/components/Component4";import Component5 from "@/components/Component5";export default {    name: 'App',    components: {        Component3,        Component4,        Component5,    },}</script>
父组件
<template>    <div class="component3">        <div class="title">Component3</div>        <div>            <span class="text-bold">count:</span>            {{count}}        </div>        <!-- 插槽 -->        <slot></slot>    </div></template><script>export default {    name: "Component3",    // 向后辈组件提供text和执行上下文this    provide(){        return{            text:this.text1,            component3:this        }    },    methods:{        addCount(){            this.count++;        }    }}</script>
子组件
<template>    <div class="component4">        <div class="title">Component4</div>、        <!-- 显示父组件的text值 -->        <div>            <span class="text-bold">text:</span>            {{text}}        </div>        <slot></slot>    </div></template><script>export default {    name: "Component4",    // 接管父组件的text值    inject:['text']}</script>
孙组件
<template>    <div class="component5">        <div class="title">Component5</div>        <!-- 显示祖组件的text值 -->        <div>            <span class="text-bold">text:</span>            {{text}}        </div>        <!-- 减少祖组件的count值 -->        <button @click="addGrandParentCount">            add count of Component3.vue        </button>    </div></template><script>export default {    name: "Component5",    // 接管祖组件的text值和执行上下文    inject:['text','component3'],    methods:{        // 通过祖组件执行上下文调用其办法        addGrandParentCount(){            this.component3.addCount();        }    }}</script>
成果

&dollar;attrs与&dollar;listeners

应用范畴

孙组件获取祖组件的值或调用祖组件事件。

应用办法

祖组件
<template>    <div class="component6">        <div class="title">Component6</div>        <div>            <span class="text-bold">count:</span>            {{count}}        </div>                        <!-- 祖组件向本人组件传递了text1与text2和一个addCount事件 -->        <component7 :text1="text" :text2="text" @addCount="addCount" />    </div></template><script>import Component7 from "@/components/Component7";export default {    name: "Component6",    components:{        Component7    },    data() {        return {            text: 'Text From Component6.vue',            count: 0        }    },    methods:{        addCount(){            this.count ++        }    }}</script>
父组件
<template>    <div class="component7">        <div class="title">Component7</div>        <div>            <span class="text-bold">text:</span>            {{text1}}        </div>        <!-- 将不被父组件prop辨认的attribute绑定到孙组件,也将祖组件的事件绑定到孙组件 -->        <component8 v-bind="$attrs" v-on="$listeners" />    </div></template><script>import Component8 from "@/components/Component8";export default {    name: "Component7",    // 父组件prop辨认了text1,因而text1不会传递到孙组件    props:{        text1:{            type:String        }    },    components:{        Component8    }}</script>
孙组件
<template>    <div class="component8">        <div class="title">Component8</div>        <div>            <span class="text-bold">text:</span>            {{text2}}        </div>        <button @click="addGrandparentCount">            add count of Component6.vue        </button>    </div></template><script>export default {    name: "Component8",    // 孙组件获取到祖组件的text2    props:{        text2:{            type:String        },    },    methods:{        // 孙组件调用了祖组件的addCount事件        addGrandparentCount(){            this.$emit('addCount');        }    }}</script>
成果

留神

$attrs 蕴含了父作用域中不作为 prop 被辨认 (且获取) 的 attribute 绑定 (class 和 style 除外)。因而当 text1 已被子组件prop获取后,在孙组件是获取不到 text1 的。