vue常見組件間通信方式

1.父組件向子組件通信:

總結:父組件通過props向下傳遞數據給子組件。注:組件中的數據共有三種形式:data、props、computed。

通信步驟:

      1.1  在父組件中定義要傳遞的數據。

      1.2 在父組件中調用子組件,並在組件上進行屬性綁定,前者自定義名稱便於子組件調用,後者是要傳遞的數據名稱。

      1.3  在組件件中通過props對象進行接收。

//父組件App組件

<template> 

     <div id="app">

         //1.2 在父組件中調用子組件,並在組件上進行屬性綁定,前者自定義名稱便於子組件調用,後者是要傳遞的數據名稱。前者childs1是自定義名稱便於子組件調用,後者childs2是要傳遞數據名

         <childs :childs1="childs2"></childs>

     </div>

</template>

<script>

import Childs from "./components/childs";

export default {

     name: 'App',

     data(){

         return{

            //1.1  在父組件定義數據。

             childs:["Henry","Bucky","Emily"]

         }

      },

     components:{ childs,}

}

</script>

//子組件 childs

<template>

     <div class="hello">

         <ul>

              //遍歷傳遞過來的值childs1,然後呈現到頁面

             <li v-for="child in childs1">{{child }}</li>

         </ul>

     </div>

</template>

<script>

export default {

     name: 'Childs',

     //1.3 在組件件中通過props對象進行接收。

     props:{

         childs1:{  //這個就是父組件中子標籤自定義名字

              type:Array,

              required:true

         }

     }

}

</script>

 

2.子組件向父組件通信:

總結:子組件通過$event給父組件發送消息,實際上就是子組件把自己的數據發送到父組件。通過事件形式。

通信步驟:     

       2.1  在子組件中定義要傳遞的數據。

       2.2 在子組件中 methods 中定義一個函數,函數內部通過 .$emit(‘定義事件名稱 childData’,‘要傳遞的數據 title’)向父組件傳遞數據。

       2.3 在子組件中 將這個函數綁定到點擊事件上。

       2.4 在父組件中在調用的子組件上同樣進行事件綁定,與子組件名稱可以不同。

       2.5 在父組件中methods 中,用這個綁定的事件去獲取數據。

 

//子組件childs

<template>

     <childs>

          //2.3 在子組件中 將這個函數綁定到點擊事件上。

         <h1 @click="childData">{{title}}</h1>

     </childs>

</template>

<script>

export default {

     name: 'Childs',

     data() {

         return {

             //2.1在子組件中定義要傳遞的數據。

             title:"Vue.js Demo"

         }

     },

     methods:{

             changeTitle() 

                      let _this. = this

                     //2.2 在子組件中 methods 中定義一個函數,函數內部通過 .$emit(‘定義事件名稱 childData’,‘要傳遞的數據 title’)向父組件傳遞數據。

                     _this.$emit("childData", this.title)

             }

     }

}

</script>

//父組件App

 <template>

     <div id="app">

          //2.4 在父組件中在調用的子組件上同樣進行事件綁定,與子組件名稱可以不同。

         <childs @titleChanged="updateTitle($event)" ></childs>

         <h2>{{title}}</h2>

     </div>

</template>

<script>

import Childs from "./components/childs";

export default {

     name: 'App',

     components:{

         childs

     }

     data(){

             return{

                 title: ""

             }

     },

    methods:{

          //2.5 在父組件中methods 中,用這個綁定的事件去獲取數據。

         updateTitle(e){

              let _this. = this

             _this.title = e

         }

     }

}

</script>

3.跨級組件間的通信:

總結:多級組件嵌套需要傳遞數據時,通常使用的方法是通過vuex。但如果僅僅是傳遞數據,而不做中間處理,可以使用$attrs/$listeners。當前組件已接收的屬性指的是當前組件在props中聲明的屬性。

$attrs:表示<父組件傳遞的屬性集合>與<當前組件已接收的屬性集合>的差集,也就是說已被當前組件接收的屬性,在下面的層級中無法再獲取到$attrs的值與inheritAttrs的值無關。

inheritAttrs: 默認true,也就是說當前組件如果沒有在props中聲明的剩餘屬性會繼承到原始html元素的屬性值上,改爲false,在當前組件中props中沒有聲明的多餘屬性不會繼承到原始html元素的屬性。

$listeners是子組件通過$emit提交的所有事件集合 (由於冒泡,還包含子組件從下一層組件獲得的所有事件),和$attrs不同的是,即使當前組件處理了子組件提交的某個事件,父組件仍然能獲取到這個事件並處理,它應該是遵循了事件冒泡的原則。

使用步驟:

          1.  在父級組件進行屬性綁定和事件綁定。屬性綁定用來向下級(子或孫組件)傳遞數據,事件綁定用來接收下級(孫組件)發送過來的數據

          2. 在子級組件下面通過porps ,來接收父級組件傳遞過來的數據。 通過v-bind="$attrs" v-on="$listeners" 向孫級組件傳遞數據。通過事件綁定來接收孫級組件發送過來的數據。

          3. 在孫級組件通過porps 接收父級組件傳遞過來的數據。定義點擊事件,通過 this.$emit('事件名稱',要發送的數據) 向上級(子級或父級)發送數據。

//父組件

<template>
        <div id="App">

            <h2>父級組件:({{name}},{{age}}</h2>
        <child
            :fatherName="name"
            :fatherAge="age"
            @toGrandFather="grandChildValue" 
            @toFather="grandChildValue">
        </child>
    </div>
</template>
<script>
import child from "./Child"
export default {
    name: "App",
    components:{child},
    data(){
            return {
                  name: "小辛",
                  age: 27
            }
    },
    methods:{
        grandChildValue(value){
                console.log("孫組件對我說:"+value)
        }
    }
}
</script>


//子組件child

<template>
    <div id="Child">
        <h2>我是子組件</h2>
        <p>我的父組件名叫{{fatherName}}</p>
        <grandson v-bind="$attrs" v-on="$listeners" @toFather="childValue"></grandson>
    </div>
</template>
<script>
import grandson from "./Grandson"
export default {
    name: "Child",
    components: {grandson},
    // 1.默認true,也就是說當前組件如果沒有在props中聲明的剩餘屬性會繼承到原始html元素的屬性值上。2.改爲false,在當前組件中props中沒有聲明的多餘屬性不會繼承到原始html元素的屬性
    inheritAttrs: false,
    // 定義:當前組件已接收的屬性指的是當前組件在props中聲明的屬性
    props: ["fatherName"],
    methods: {
        childValue(value){
                  console.log("子組件對我說:"+value)
        }
    }
}
</script>

//孫組件grandson

<template>
    <div id="grandson">
        <h2>我是孫組件</h2>
        <p>我父組件定義的name名叫{{fatherName}},今年{{fatherAge}}歲</p>
        <button @click="toGrandFather">叫爺爺</button>
        <button @click="toFather">叫爸爸</button>
    </div>
</template>
<script>
export default {
    name: "Grandson",
    props: ["fatherAge","fatherName"],
    methods: {
         toGrandFather(){
                this.$emit("toGrandFather","App.vue,我是您孫組件")
        },
         toFather(){
            this.$emit("toFather","Child.vue,我是您子組件")
        }
    }
}
</script>

 

4.輕量級任何組件間(父子、兄弟、跨級)的通信:

 總結:通過一個空的Vue實例作爲$EventBus中央事件總線(事件中心),用它來觸發事件和監聽事件,巧妙而輕量地實現了任何組件間的通信,包括父子、兄弟、跨級。當我們的項目比較大時,可以選擇更好的狀態管理解決方案 vuex。EventBus事件不會隨着組件的關閉而自行銷燬,所以當路由切換時,EventBus事件會不停的觸發,如果數據量比較多的時候,可能會比較影響性能吧,所以需要及時銷燬所綁定的EventBus事件。在destroyed()生命週期時執行this.$EventBus.$off('事件名稱') 進行事件銷燬。

通信步驟:

      3.1  首先在main.js將$EventBus綁定在vue實例上。Vue.prototype.$EventBus = new Vue()。在組件出通過this.$EventBus調用。

      3.2  在任意A組件發出數據,this.$EventBus.$emit('事件名','數據');

      3.3  在任意B組件接收數據,this.$EventBus.$on(‘與A組件定義的事件名保持相同',data => {});

//父組件

<template>

     <div id="app">

        <child-a></child-a>

        <child-b></child-b>

        <child-c></child-c>

         <div>

                 <p>{{name }}</p>

                  <p>{{sex}}</p>

                  <p>{{age}}</p>

         <div>

     </div>

</template>

<script>

import child-a from "./components/child-a";

import child-b from "./components/child-b";

import child-c from "./components/child-c";

export default {

     name: 'App',

     components:{

         child-a ,

         child-b,

         child-c

     },   

     data(){

          return {

               name : '',

               sex: '',

               age: ''   

         }

     },     

     mounted(){

           let _this. = this

           _this.fromDataChildB()

           _this.fromDataChildC()

           _this.fromDataChildA()

     },   

    methods:{

              //父組件接收來自任意子組件B的發送的數據

              fromDataChildB(){         

                 let _this. = this

                  _this.$EventBus.$on('sendName', (data)=>{

                        _this.name= data.name

                   })

             },  

            //父組件接收來自任意子組件C的發送的數據

           fromDataChildC(){         

                 let _this. = this

                  _this.$EventBus.$on('sendSex', (data)=>{

                        _this.sex= data.sex

                   })

             },

              //父組件接收來自任意子組件A的發送的數據

             fromDataChildA(){         

                 let _this. = this

                  _this.$EventBus.$on('sendAge', (data)=>{

                        _this.age= data.age

                   })

             }

    },

    destroyed(){

         //事件銷燬

         let _this =this

          _this.$EventBus.$off('sendName')

          _this.$EventBus.$off('sendSex')

          _this.$EventBus.$off('sendAge')

    }

}

</script>

//組件child-a

<template>

     <div id="childA">

         <div>{{age}}</div>

        <button  @click="toSendChildB"></button>

     </div>

</template>

<script>

export default {

     name: 'childA',

     data(){

          return {

               age: '',

               name : 'xiaoXin',

         }

     },    

   mounted(){

           let _this. = this

           _this.fromDataChildC()

     },

     methods:{

              //接收來自統計C組件發送的數據

              fromDataChildC(){         

                 let _this. = this

                  _this.$EventBus.$on('sendAge', (data)=>{

                        _this.age= data.age

                   })

             },

              //在任意A組件發出數據,this.$EventBus.$emit('事件名','數據');

              toSendChildB(){

                   let _this. = this

                   _this.$EventBus.$emit('sendName', _this.name)

             }

     },   

    destroyed(){

          let _this =this

          _this.$EventBus.$off('sendAge')

    }

}

</script>

//組件child-b

<template>

     <div id="childB">

        <div>{{name}}</div>

        <button  @click="toSendChildC"></button>

     </div>

</template>

<script>

export default {

     name: 'childB',

     data(){

          return {

               name : '',

               sex: 'man',

         }

     },    

    mounted(){

           let _this. = this

           _this.fromDataChildA()

     },

     methods:{

              //接收來自統計A組件發送的數據

              fromDataChildA(){

                   let _this. = this

                   _this.$EventBus.$on('sendName', (data)=>{

                        _this.name = data.name

                   })

             },

              //在任意B組件發出數據,this.$EventBus.$emit('事件名','數據');

              toSendChildC(){

                   let _this. = this

                   _this.$EventBus.$emit('sendSex', _this.sex)

             }

     },     

    destroyed(){

          let _this = this 

          _this.$EventBus.$off('sendName')

    }

}

</script>

//子組件child-c

<template>

     <div id="childC">

        <div>{{sex}}</div>

        <button  @click="toSendChildA"></button>

     </div>

</template>

<script>

export default {

     name: 'childC',

     data(){

          return {

               sex: '',

               age: '27'

         }

     },    

    mounted(){

           let _this. = this

           _this.fromDataChildB()

     },

     methods:{

              //接收來自統計B組件發送的數據

              fromDataChildB(){

                   let _this. = this

                   _this.$EventBus.$on('sendSex', (data)=>{

                        _this.sex= data.sex

                   })

             },

              //在任意C組件發出數據,this.$EventBus.$emit('事件名','數據');

              toSendChildA(){

                   let _this. = this

                   _this.$EventBus.$emit('sendAge', _this.age)

             }

     },    

   

destroyed(){

          let _this = this 

         _this.$EventBus.$off('sendSex')

    }

}

</script>

5.狀態管理器Vuex——萬能組件間通信:

總結:Vuex實現了一個單向數據流,在全局擁有一個State存放數據,如果需要對state做計算,可以在getters中進行。當組件要更改State中的數據時,必須通過Mutation進行,Mutation同時提供了訂閱者模式供外部插件調用獲取State數據的更新。而當所有異步操作(常見於調用後端接口異步獲取更新數據)或批量的同步操作需要走Action,但Action也是無法直接修改State的,還是需要通過Mutation來修改State的數據。最後,根據State的變化,渲染到視圖上。

通信步驟:

          1.創建store.js 文件,與main.js文件同級。

          2.安裝vuex庫,在main.js文件裏進行引入和註冊到vue實例中。

                   安裝:npm install --save vuex

                   引入:在store.js 中引入vue和vuex  ,,

                   初始化:在store.js 中 Vue.use(vuex)

                   註冊:在main.js 文件引入 store.js ,並註冊到vue根實例中    

                 import store from './store/store.js'

           new Vue({

                  el: '#app',

                    store,

                    components: { App },

                    template: '<App/>'

              })

         3. 創建store模塊,

              export const store =    new Vuex.Store({  //最重要的事就是保存應用的狀態

                  state: {  //狀態存儲,頁面狀態管理容器對象

                        num: 0

                  },

                   getters: {

                       doubleNum(state){ //對狀態進行計算,state對象讀取方法

                            return state.num* 2

                         },

                      },

               mutations: {

                     increment(state){ //state狀態改變並做同步提交操做

                       state.num ++

                  },

                  actions: {

                        submitNum({commit}){ //異步提交mutation中的狀態,commit是context下的一個方法

                             commit('increment')

                         }

                   }

                 })

         在組件中調用:

                調用原始的狀態:this.$store.state.num

                調用gettes計算後的狀態:this.$store.gettes.doubleNum

                調用mutations改變後的狀態:this.$store.mutations.increment

                調用actions進行異步提交狀態:this.$store.dispacth('submitNum')

 Vuex與localStorage的配合:vuex 是 vue 的狀態管理器,存儲的數據是響應式的。但是並不會保存起來,刷新之後就回到了初始狀態。具體做法應該在vuex裏數據改變的時候把數據拷貝一份保存到localStorage裏面,刷新之後,如果localStorage裏有保存的數據,取出來再替換store裏的state。由於vuex裏,我們保存的狀態,都是數組,而localStorage只支持字符串,所以需要用JSON轉換。我們常用二者的結合做用戶登錄和用戶登出,以及登錄狀態保留。

vuex最好的用法是模塊化Module,將不同的的狀態單獨處理。減少彼此的耦合度。

 

本文如果存在錯誤之處歡迎指出。如有更好的vue.js組件間通信方式感謝指導。感謝觀看。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章