Vue 組件通信的 8 種方式

前言

做了半年的公司系統,終於就在前天上線了。後期改 BUG 時間拖得太長了,出現的大部分 BUG 是 前端 與 後端 信息不對稱導致的,邏輯性錯誤很不多,用戶體驗上稍微差點,畢竟第一次做這麼大的系統 (100w+),通過這次系統的開發,總結了不少經驗,如何更好的跟後端人員協作開發以及如何設計來提高用戶體驗上,之前自己做開發沒關注這方面,只注重功能實現,後期的這塊多補補。

項目上線後,接下來就是後期的維護更新了,最近時間終於不是之前那麼忙碌了,簡單的對系統做了下覆盤。由於項目採用的技術棧是Vue, 平常開發只注重功能實現了,接下來陸續會對 Vue 深入分析, 來封裝常用業務組件,以及Vue源碼解析    本章將是對 Vue 組件通信的 8 方法總結,日常開發組件通信密切,熟悉組件通信可以更好的開發業務。

Vue 組件之間傳值

1. 父組件 向 子組件 傳遞值

子組件接收的父組件的值分爲引用類型和普通類型兩種:

#父組件

<template>
  <div>
    <!-- 傳遞值 -->
    <Test
     :obj="obj" 
     info="測試"/>
  </div>
</template>

<script>
// 引入子組件
import Test from "../components/Test.vue";
export default {
  name: "about",
  // 註冊子組件
  components: {
    Test,
  },
  data() {
    return {
      obj: {
        code: 200,
        title: "前端自學社區",
      },
    };
  },
};
</script>
<template>
    <div>
        <h1>{{obj.code}}</h1><br>
        <h2>{{obj.title}}</h2>
        <h3>{{info}}</h3>
    </div>
</template>

<script>
    export default {
        name:'test',
        props:{
            obj:Object,
            info: [String,Number]  //info值爲其中一種類型即可,其他類型報警告
        }
    }
</script>

由於 Vue 是 單向數據流, 子組件 是不能直接 修改 父組件 的 值。

2. 子組件 向父組件傳遞值

子組件通過綁定事件,通過 this.$emit('函數名',傳遞參數)

#父組件

<Test
     :obj="obj" 
     info="測試"
     @modify="modifyFatherValue"/>

<script>
// 引入子組件
import Test from "../components/Test.vue";
export default {
  name: "about",
  // 註冊子組件
  components: {
    Test,
  },
  data() {
    return {
      msg:'我是父組件'
    };
  },
  methods:{
    // 接受子組件傳遞來的值,賦值給data中的屬性
    modifyFatherValue(e){
      this.msg = e
    }
  }
};
</script>
# 子組件

<button @click="modifyValue">修改父組件的值</button>


<script>
    export default {
        name:'test',
        methods:{
            modifyValue(){
                this.$emit('modify','子組件傳遞過來的值')
            }
        }
    }
</script>

3. 父組件 通過 $refs / $children 來獲取子組件值

$refs :

$children :

示例 Text 組件

<script>
    export default {
        name:'test',
        data() {
            return {
                datas:"我是子組件值"
            }
        },
        props:{
            obj:Object,
            info: [String,Number]
        },
        methods:{
            getValue(){
                console.log('我是Test1')
            }
        }
    }
</script>

示例 Text2 組件

<template>
    <div>
        <h1>我是Test2</h1>
    </div>
</template>

<script>
    export default {
        name:'test',
        data() {
            return {
                datas:"我是Test2"
            }
        },
        created(){
         console.log( this.$parent.obj ) 
         this.$parent.getQuery()
        },
        methods:{
            getTest2(){
                console.log(this.datas)
            }
            
        }
    }
</script>

refs

<template>
  <div>
   // 給子組件上綁定 ref  
    <Test
      ref="son"
    />
   <Test2/>
  </div>
</template>

// 通過 $refs 示例來獲取 子組件的屬性和方法

 console.log( this.$refs.son.datas) 

 this.$refs.son.getValue()

$children

//  通過 $children  來獲取 子組件的屬性和方法
      this.$children[0].getValue(); // 我是 Test1
      this.$children[1].getTest2();  //我是 Test2
      console.log(`---------${this.$children[1].datas}`); //我是Test2

4. 子組件 通過 $parent 來獲取父組件實例的屬性和方法

<script>
    export default {
        name:'test',
        created(){
         console.log( this.$parent.obj ) 
         this.$parent.getQuery()
        },
        
    }
</script>

5. $attrs 和 $listeners 獲取父組件實例屬性和方法 (組件嵌套情況下使用)

$attrs:包含了父作用域中不被認爲 (且不預期爲) props 的特性綁定 (class 和 style 除外),並且可以通過 v-bind=” $attrs” 傳入內部組件。當一個組件沒有聲明任何 props 時,它包含所有父作用域的綁定 (class 和 style 除外)。

$listeners:包含了父作用域中的 (不含 .native 修飾符) v-on 事件監聽器。它可以通過 v-on=”$listeners” 傳入內部組件。它是一個對象,裏面包含了作用在這個組件上的所有事件監聽器,相當於子組件繼承了父組件的事件。

使用場景:多層嵌套組件的情況下使用,可以避免使用 Vuex 來做數據處理, 使用 v-bind="$attrs" v-on="$listeners" 很方便達到業務數據傳遞。

父組件

<template>
    <div>
        <Test3  
        :status="status" 
        :title="title"
        @getData="getData" />
    </div>
</template>

<script>
import Test3 from "../components/Test3.vue";
    export default {
        name:'person',
        data(){
            return {
                title:'personal 組件',
                status: false
            }
        },
        methods:{
          getData(){
              console.log(this.title)
          }  
        },
        components:{
            Test3
        }
    }
</script>

子組件 1

<template>
  <div>
    <h1>Test3 組件</h1>
    <br /><br />
    // 通過 $attrs(屬性,除了【props中定義的屬性】)  和 $listeners(方法)  來給嵌套子組件傳遞父組件的屬性和方法
    <Test4   v-bind="$attrs" v-on="$listeners"/>
  </div>
</template>

<script>
// 引入子子組件   
import Test4 from "../components/Test4";
export default {
  name: "test3",
  props: ["title"],
  components: {
    Test4,
  },
  created() {
    console.log(this.$attrs);  //{status: false}
    console.log("-----------");
    console.log(this.$listeners); // {getData: ƒ}
  },
};
</script>

嵌套子組件

<template>
    <div>
        <h1>Test4 組件</h1>
    </div>
</template>

<script>
    export default {
        name:'test4',
        created(){
            console.log('-----Test4------')
            console.log(this.$attrs) //{status: false}
            console.log(this.$listeners) // {getData: ƒ}
        }
    }
</script>

6. 跨組件之間傳值

通過新建一個 js 文件,導入 vue , 導出 vue 實例;然後通過 給導出的實例 上綁定事件 $emit 事件 , 然後再通過 $on 監聽觸發的事件,這樣就可以達到全局組件數據共享。

使用場景:

它可以滿足任意場景傳遞數據, 父子組件傳值 , 子父傳值 , 兄弟組件之間傳值 , 跨級組件之間傳值 .

通信數據比較簡單時,可以採用這種 方案,項目比較龐大,可以採用 Vuex .

vue .js

/*
 * @Description: 
 * @Author: ZhangXin
 * @Date: 2021-01-22 15:48:56
 * @LastEditTime: 2021-01-22 15:51:24
 * @LastEditors: ZhangXin
 */

 import Vue from 'vue'

 export default new Vue()

組件 A

<!--
 * @Description: 
 * @Author: ZhangXin
 * @Date: 2021-01-22 14:44:17
 * @LastEditTime: 2021-01-22 16:25:33
 * @LastEditors: ZhangXin
-->

<template>
    <div>  
        <button @click="changeValue">改變</button>
    </div>
</template>

<script>
import zxVue from '../util/newVue.js';
    export default {
        name:'person',
        data(){
            return {
                title:'personal 組件',
                status: false
            }
        },
        methods:{
          changeValue(){
             // 通過給 vue實例綁定事件
             zxVue.$emit("getTitle", this.title)   
          }  
        }
    }
</script>

組件 C

<!--
 * @Description: 
 * @Author: ZhangXin
 * @Date: 2021-01-22 15:07:30
 * @LastEditTime: 2021-01-22 16:26:38
 * @LastEditors: ZhangXin
-->
<template>
  <div>
    <h1>Test4 組件</h1>
    <h1>{{ title }}</h1>
  </div>
</template>

<script>
import zxVue from "../util/newVue";
export default {
  name: "test4",
  data() {
    return {
      title: "test4",
    };
  },
  mounted(){
    // 通過 vue 實例.$on  監聽事件名,來接收跨級組件傳遞過來的值
    zxVue.$on("getTitle"(item) ={
      this.title = item;
      console.log(item)
    });

  }
};
</script>

7. Vuex

這裏就不介紹了,完了單獨寫一篇文章精講 Vuex

8. provide 和 inject 實現父組件向子孫孫組件傳值。(層級不限)

provide 和 inject 這對選項需要一起使用,以允許一個祖先組件向其所有子孫後代注入一個依賴,不論組件層次有多深,並在起上下游關係成立的時間裏始終生效。

provide :

inject :

使用場景:

provide/inject可以輕鬆實現跨級訪問父組件的數據

# provide
//對象
provide:{
    name:'測試'
}
//返回對象的函數
provide(){
    return {
        name: '測試'
    }
}

#inject
inject:['name']

父組件

<!--
 * @Description: 
 * @Author: ZhangXin
 * @Date: 2021-01-22 23:24:16
 * @LastEditTime: 2021-01-22 23:49:50
 * @LastEditors: ZhangXin
-->
<template>
    <div>
        <h1>我是父組件</h1>
        <Son />
    </div>
</template>

<script>
import Son from '../components/son/SonOne'
    export default {
        name:'father',
        provide(){
            return {
                titleFather: '父組件的值'
            }
        },
        components:{
            Son
        },
        data(){
            return{
                title:'我是父組件 '
            }
        },
        
    }
</script>

子組件

<template>
    <div>
        <h1>我是子孫組件</h1>
       
    </div>
</template>

<script>
import SonTwo from '../son/SonTwo'
    export default {
        name:'sonone',
        components:{
           SonTwo
        },
        inject:['titleFather'],
        created(){
             console.log(`${this.titleFather}-----------SonTwo`)
        },
        data(){
            return{
                title:'我是子組件 '
            }
        },
        
    }
</script>

子孫組件

<template>
    <div>
        <h1>我是子孫組件</h1>
       
    </div>
</template>

<script>
import SonTwo from '../son/SonTwo'
    export default {
        name:'sonone',
        components:{
           SonTwo
        },
        inject:['titleFather'],
        created(){
             console.log(`${this.titleFather}-----------SonTwo`)
        },
        data(){
            return{
                title:'我是子組件 '
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/dWV5pIpY7Gm2w5vE3ZkeJQ