沒有廢話的vue高級進階( 二 ) 8種組件通訊詳解

猛獸老是獨行,牛羊才三五成羣。      -------魯迅

vue組件通訊的重要性無需多言。。。可是你確定沒有所有掌握,因此這第二篇文章應運而生

props和$emit

props父傳子,$emit子傳父,看下邊代碼,清澈的像少女的眼眸。。。emmmjavascript

Vue.component('child',{
        data(){
            return {
                mymessage:this.message
            }
        },
        template:` <div> <input type="text" v-model="mymessage" @input="passData(mymessage)"> </div> `,
        props:['message'],//獲得父組件傳遞過來的數據
        methods:{
            passData(val){
                //觸發父組件中的事件
                this.$emit('getChildData',val)
            }
        }
    })
┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┅┄*
	Vue.component('parent',{
        template:` <div> <p>this is parent compoent!</p> <child :message="message" v-on:getChildData="getChildData"></child> </div> `,
        data(){
            return {
                message:'張不慫'
            }
        },
        methods:{
            //執行子組件觸發的事件
            getChildData(val){
                console.log(val)
            }
        }
    })
┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┅┄*

	 // 掛載
    var app=new Vue({
        el:'#app',
        template:` <div> <parent></parent> </div> `
    })
複製代碼

中央事件總線new Bus

新建一個Vue事件bus對象,而後經過bus.$emit觸發事件,bus.$on監聽觸發的事件。vue

Vue.component('brother1',{
        data(){
            return {
                mymessage:'hello brother1'
            }
        },
        template:`
            <div>
                <p>this is brother1 compoent!</p>
                <input type="text" v-model="mymessage"
                @input="passData(mymessage)"> 

            </div>
        `,
        methods:{
            passData(val){
                //觸發全局事件globalEvent
                bus.$emit('globalEvent',val)

            }
        }
    })
 ┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┅┄*

    Vue.component('brother2',{
        template:`
            <div>
                <p>this is brother2 compoent!</p>
                <p>brother1傳遞過來的數據:{{brothermessage}}</p>
            </div>
        `,
        data(){
            return {
                mymessage:'hello brother2',

                brothermessage:''
            }
        },
        mounted(){
            //綁定全局事件globalEvent
            bus.$on('globalEvent',(val)=>{
                this.brothermessage=val;
            })
        }
    })
┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┅┄*

    //中央事件總線
    var bus=new Vue();

    var app=new Vue({
        el:'#app',
        template:`
            <div>
                <brother1></brother1>
                <brother2></brother2>
            </div>
        `
    })
複製代碼

provide和inject

父組件中經過provider來提供變量,而後在子組件中經過inject來注入變量。不論子組件有多深,只要調用了inject那麼就能夠注入provider中的數據。而不是侷限於只能從當前父組件的prop屬性來獲取數據,只要在父組件的生命週期內,子組件均可以調用。java

Vue.component('child',{
        inject:['parent_var'],//獲得父組件傳遞過來的數據
        data(){
            return {
                mymessage:this.parent_var
            }
        },
        template:`
            <div>
               {{ message }}
            </div>
    })
┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┅┄*
    Vue.component('parent',{
        template:`
            <div>
                <child></child>
            </div>
        `,
        provide:{
            // 看你想傳遞啥了,這裏不寫固定的緣由是爲了防止限制你們的思惟
            /*
            好比你能夠把用戶登陸信息存儲在App.vue中,能夠把
            provide:{app:this}注入,後續全部組件經過inject:['app'],
            就能夠直接經過app.userInfo拿到用戶信息
            */
            parent_var:'隨便什麼均可以(能夠是this,能夠是data中的數據)'
        },
        data(){
            return {
                message:'hello'
            }
        }
    })
┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┄┅┄┅┄┅┄┅┄*
    var app=new Vue({
        el:'#app',
        template:`
            <div>
                <parent></parent>
            </div>
        `
    })
複製代碼

$attrs和$listeners

仍是多層的場景,App.vue-->A—>B,若是App直接想給B傳遞數據該怎麼辦?Vue 2.4開始提供了和attrs和listeners來解決這個問題,可以讓組件App直接傳遞數據給組件B。我將代碼中關鍵點已經標註出, // ******關鍵點*****vuex

app.vue引入A組件bash

<template>
  <div id="app">
    {{app}}
    // ******關鍵點*****
    <A :app="app" @test="doTest"/>
  </div>
</template>

<script>
import A from "./components/A";

export default {
  name: "App",
  data() {
    return {
      app: "我是App的數據"
    };
  },
  components: {
    A
  },
  methods: {
    doTest() {
      console.log(this.app)
    }
  }
};
複製代碼

A.vue引入B組件app

<template>
  <div class="hello">
    <h6>這裏是A組件</h6>
    <p>$attrs: {{$attrs}}</p>
    <p>$listeners: {{$listeners}}</p>
     // ******關鍵點***** v-bind傳遞的都是$attrs,v-on傳遞的都是$listeners
    <B v-bind="$attrs" v-on="$listeners"/>
  </div>
</template>

<script>
import B from "./B";

export default {
  name: "A",
  props: {
    msg: String
  },
  components: { B },
  mounted() {
    console.log(this.$listeners);
  }
};
</script>
複製代碼

B組件編輯器

<template>
  <div class="hello">
    <h6>這裏是B組件</h6>
     // ******關鍵點*****
    <p>$attrs: {{$attrs}}</p>
  </div>
</template>

<script>

export default {
  name: "B",
  props: {
    msg: String
  },
  mounted() {
   // ******關鍵點*****
   // 爲啥這裏直接能emitApp組件傳遞的test呢?
   // 由於在A組件中有一個關鍵操做是  <B v-bind="$attrs" v-on="$listeners"/>
    this.$emit("test");
  }
};
</script>
複製代碼

$parent和$children

分別是得到父組件和子組件的實例ide

Vue.component('child',{
        props:{
            value:String, //v-model會自動傳遞一個字段爲value的prop屬性
        },
        data(){
            return {
                mymessage:this.value
            }
        },
        methods:{
            changeValue(){
                this.$parent.message = this.mymessage;//經過如此調用能夠改變父組件的值
            }
        },
        template:`
            <div>
                <input type="text" v-model="mymessage" @change="changeValue"> 
            </div>
    })
    Vue.component('parent',{
        template:`
            <div>
                <p>this is parent compoent!</p>
                <button @click="changeChildValue">test</button >
                <child></child>
            </div>
        `,
        methods:{
            changeChildValue(){
                this.$children[0].mymessage = 'hello';
            }
        },
        data(){
            return {
                message:'hello'
            }
        }
    })
    var app=new Vue({
        el:'#app',
        template:`
            <div>
                <parent></parent>
            </div>
        `
    })
複製代碼

v-model

父組件經過v-model傳遞值給子組件時,會自動傳遞一個value的prop屬性,在子組件中經過this.$emit(‘input’,val)自動修改v-model綁定的值post

Vue.component('child',{
        props:{
            value:String, //v-model會自動傳遞一個字段爲value的prop屬性
        },
        data(){
            return {
                mymessage:this.value
            }
        },
        methods:{
            changeValue(){
                this.$emit('input',this.mymessage); //經過如此調用能夠改變父組件上v-model綁定的值
            }
        },
        template:`
            <div>
                <input type="text" v-model="mymessage" @change="changeValue"> 
            </div>
    })
    Vue.component('parent',{
        template:`
            <div>
                <p>this is parent compoent!</p>
                <p>{{message}}</p>
                <child v-model="message"></child>
            </div>
        `,
        data(){
            return {
                message:'hello'
            }
        }
    })
    var app=new Vue({
        el:'#app',
        template:`
            <div>
                <parent></parent>
            </div>
        `
    })
複製代碼

boradcast和dispatch

vue1.0中提供了這種方式,但vue2.0中沒有,但不少開源軟件都本身封裝了這種方式,好比min ui、element ui, broadcast是向特定的父組件,觸發事件,dispatch是向特定的子組件觸發事件,本質上這種方式仍是使用遞歸對on和emit的封裝,但在一些基礎組件中卻很實用。注意:全部組件的名稱不能重複!!!ui

function broadcast(componentName, eventName, params) {
  this.$children.forEach(child => {
    var name = child.$options.componentName;

    if (name === componentName) {
      child.$emit.apply(child, [eventName].concat(params));
    } else {
      broadcast.apply(child, [componentName, eventName].concat(params));
    }
  });
}

function dispatch(componentName, eventName, params) {
  		var parent = this.$parent;
      var name = parent.$options.componentName;
      while (parent && (!name && name !== componentName)) {
        parent = parent.$parent;
        if (parent) {
          name = parent.$options.componentName;
        }
      }
      if (parent) {
        parent.$emit.apply(parent, [eventName].concat(params));
      }
}
export default {
  methods: {
    dispatch(componentName, eventName, params) {
      dispatch.call(this, componentName, eventName, params);
    },
    broadcast(componentName, eventName, params) {
      broadcast.call(this, componentName, eventName, params);
    }
  }
};
複製代碼

vuex

對於vuex再也不作過多的贅述。。。

第二章很是全面的講解了vue炒雞重要的一個技能,組件通訊,我說這一篇全面你們應該沒意見吧?好了就這樣...

以爲對你有幫助,不妨點個

,後續持續輸出這種簡短有效的文章,幫助你用最短的時間內掌握最多的內容,畢竟誰不喜歡一勞永逸不是? ❥(^_-) thank you ~

後續目錄

沒有廢話的vue高級進階( 一 ) 組件精髓概述

沒有廢話的vue高級進階( 二 ) 8種組件通訊詳解

沒有廢話的vue高級進階( 三 ) 組件高級用法及最佳實踐

相關文章
相關標籤/搜索