最全Vue組件間通信方式總結,Vue組件化

Vue組件化, 組件間通信方式

1.0 父子組件之間通信

1.1 父傳子

1.1.1 props 方式傳參.

props 通信的方式是 父級組件和子級組件之間通信的一種方式, 具體使用方法如下

  1. 子組件接收數據時的方式有 props: [’’] 數組的方式**
  2. 或者通過 props:{} 對象的方式接收數據

🏴 注意: 子組件中的函數或方法如果要操作父組件的數據的時候,通常是在父組件定義一個方法, 把這個方法通過標籤屬性props傳給子組件, 在子組件中調用該方法把參數傳遞過去,完成子組件對父組件數據的操作

案例代碼如下:

Parent 父組件:

<template>
    <div>
        <h1 style="color: pink">我是parent組件, 下面是Son組件</h1>
        <Son msg="我是props 方式給子組件傳參"/>
    </div>
</template>
<script>
    import Son from './Son'
    export default {
        name: "Parent",
        components: {
            Son,
        },
        methods: {
        },
    }
</script>
<style scoped>
</style>

children子組件:

<template>
    <div>
        <h3>我是son組件: {{msg}}</h3>
    </div>
</template>
<script>
    export default {
        name: "Son",
        props: ['msg'],
        mounted() {
            console.log(this.msg);
        }
    }
</script>
<style scoped>
</style>

1.1.2 自定義函數傳參

自定義函數的方式, 可以實現父組件的函數在子組件中觸發, 這種方式可以在子組件中, 再調用函數的是候, 給父組件傳遞數據

// 1. 在 Vue中也可以通過自定義函數的方式和子組件之間通信, 一般會在自定義函數的函數名字之前添加一個 @ 符號, 寫法如下.
	<!-- 父組件自定義一個函數, 通過標籤屬性傳遞給子組件 -->
    <Son @selfDefineEvent="selfDefineEvent"/>
        
// 2. 這種方式, 在子組件中, 可以直接通過  this.$emit('自定義函數名', 參數) 方法分發事件. (相當於觸發傳遞過來的事件)
        
/**
 * 自定義事件通信方式的方式
 * 1. 在父組件中定義一個事件函數, 通過標籤屬性的方式把該自定義事件傳給子組件
 * 2. 在子組件中直接通過 this.$emit() 來觸發事件.
 * 3. 其本質是在子組件調用該自定義事件的時候, 通過傳遞參數的方式, 把數據傳遞給父組件
*/

案例代碼如下:

Parent父組件:

<template>
    <div>
        <h1 style="color: pink">我是parent組件, 下面是Son組件</h1>
        <!-- 父組件自定義一個函數 -->
        <Son @selfDefineEvent="selfDefineEvent"/>
    </div>
</template>
<script>
    import Son from './Son'
    export default {
        name: "Parent",
        components: {
            Son,
        },
        methods: {
            selfDefineEvent(...params) {
                console.log(...params);
            }
        },
    }
</script>
<style scoped>
</style>

Son 子組件代碼:

<template>
    <div>
        <h3>我是son組件</h3>
        <button @click="handleClick">Son 組件內點擊觸發父組件 自定義函數</button>
    </div>
</template>
<script>
    export default {
        name: "Son",
        methods: {
            handleClick() {
                // 在子組件內, 直接通過 $emit 觸發父組件自定義的函數
                this.$emit('selfDefineEvent', '我是自定義函數參數',123,'mm')
            }
        },
    }
</script>
<style scoped>
</style>

原理:

1. // 在vue中, 每一個組件, 包括 App 組件, 如果你在組件的聲明週期函數中 打印 console.log(this), 會打印出是一個 VueComponent{} 對象, 代表當前的組件實例對象

2. // 而 在 vue 中, 所有的組件對象, 包括 App 等其他一些子組件的實例 都是 Vue 這個組件的實例對象的子對象, 他們之間存在繼承的關係.

3. // 在 vue中, 通過 @事件名,  自定義的事件, 都會放在 Vue 這個組件的 prototype 中, 所以 Vue組件的實例 vm對象及其所有 子組件實例對象,都可以找到 這個自定義事件. 所以就可以在它的子組件中通過  原型鏈就可以找到   Vue 組件對象的 $emit 這個方法, 完成通信.
		this.$emit('自定義事件名字', 參數);

1.2 子傳父

vue 組件之間通信之 - 子組件傳遞數據給父組件.

即: 父組件訪問子組件的數據.

1.2.1 ref 實現: 父組件訪問子組件數據

通過 ref 屬性給子組件做個標識, 可以獲取到子組件, 進而可以獲取到子組件data 中的數據, 也可以獲取到子組件當中的相關方法.

代碼示例如下:

Parent組件

<template>
    <div>
        <h1 style="color: pink">我是parent組件, 下面是Son組件</h1>
        <Son ref="sonRef" msg="我是父組件傳遞給子組件的msg屬性..."/>
    </div>
</template>
<script>
    import Son from './Son'

    export default {
        name: "Parent",
        components: {
            Son
        },
        mounted() {
            console.log('父組件想要獲取子組件數據---->> ',this.$refs.sonRef.sonData); // 獲取子組件 data內的數據
            console.log('父組件想要獲取子組件數據---->> ',this.$refs.sonRef.msg); // 獲取子組件 pros 內的數據
            this.$refs.sonRef.sayHi() // 調用子組件的方法
        }
    }
</script>
<style scoped>
</style>

Son 組件

<template>
    <h3>我是son組件</h3>
</template>
<script>
    export default {
        name: "Son",
        props:['msg'],
        data() {
            return {
                sonData: '我是子組件的數據'
            }
        },
        methods: {
            sayHi() {
                console.log('%c hello parents, I am your son ...', 'color:pink');
            }
        }
    }
</script>
<style scoped>
</style>

1.2.2 $children實現: 父組件訪問子組件數據

Vue.js官網關於 $children 的介紹:

- 類型: Array<Vue instance>
- 只讀
- 詳細:
	當前實例的 "直接" 子組件. 需要注意的是, `$children`"並不保證順序, 也不是響應式的.",如果你發現自己正在嘗試使用 `$children` 來進行數據綁定, 考慮使用一個數組配合 `v-for` 來生成子組件, 並且使用 Array 作爲真正的來源.

通過$children的方式獲取到當前組件的所有子組件, 用索引獲取指定子組件, 然後獲取到對應子組件的 props,data 以及method 方法等

但是: 使用 $children 的這種方式, vue中不一定是按照順序的, vue中通過$children獲取到的子組件是不保證這裏取到子組件的順序的.

Parent組件代碼如下

<template>
    <div>
        <h1 style="color: pink">我是parent組件, 下面是Son組件</h1>
        <Son ref="sonRef" msg="我是父組件傳遞給子組件的msg屬性..."/>
    </div>
</template>
<script>
    import Son from './Son'

    export default {
        name: "Parent",
        components: {
            Son
        },
        mounted() {
            console.log(this.$children[0].msg); // 訪問子組件 props 屬性
            console.log(this.$children[0].sonData); // 訪問子組件 data
            this.$children[0].sayHi() // 訪問子組件 method 方法
        }
    }
</script>
<style scoped>
</style><template>
    <div>
        <h1 style="color: pink">我是parent組件, 下面是Son組件</h1>
        <Son ref="sonRef" msg="我是父組件傳遞給子組件的msg屬性..."/>
    </div>
</template>
<script>
    import Son from './Son'

    export default {
        name: "Parent",
        components: {
            Son
        },
        mounted() {
            console.log(this.$children[0].msg); // 訪問子組件 props 屬性
            console.log(this.$children[0].sonData); // 訪問子組件 data
            this.$children[0].sayHi() // 訪問子組件 method 方法
        }
    }
</script>
<style scoped>
</style>

子組件代碼同上面子組件的代碼

1.2.3 $emit事件派發與監聽

注意: 事件派發與監聽, 雖然能在父組件中獲取到子組件派發事件所傳遞的數據, 但是實際上, 還是在 子組件上監聽的事件. 即: 誰派發事件, 誰來監聽事件.

Parent 組件如下

<template>
    <div>
        <h1 style="color: pink">我是parent組件, 下面是Son組件</h1>
        <!-- 監聽子組件派發的事件 -->
        <Son @eventEmit="handleEventEmit" ref="sonRef" msg="我是父組件傳遞給子組件的msg屬性..."/>
    </div>
</template>
<script>
    import Son from './Son'

    export default {
        name: "Parent",
        components: {
            Son
        },
        mounted() {
        },
        methods: {
            handleEventEmit(params) {
                console.log('父組件監聽到子組件派發的數據 -->', params);
            }
        }
    }
</script>
<style scoped>
</style>

Children組件如下

<template>
    <div>
        <!-- 子組件綁定派發事件 -->
        <h3 @click="$emit('eventEmit','我是事件派發想要傳遞的數據123.')">我是son組件</h3>
    </div>
</template>
<script>
    export default {
        name: "Son",
        props: ['msg'],
        data() {
            return {
                sonData: '我是子組件data 的數據...'
            }
        },
        methods: {
            sayHi() {
                console.log('%c hello parents, I am your son ...', 'color:pink');
            }
        }
    }
</script>
<style scoped>
</style>

2.0 兄弟組件之間的通信

2.1 $emit$on , 通過共同父組件實現兄弟組件通信

藉助共有父組件的方式來實現.

用事件的派發與監聽, 通過共同父組件來派發和監聽事件, 實現兄弟組件之間通信

下面案例實現 Son組件與 Son1組件間通信, 共同父組件 Parent

Parent 組件如下

<template>
    <div>
        <h1 style="color: pink">我是parent組件, 下面是Son組件</h1>
        <!-- 監聽子組件派發的事件 -->
        <Son @eventEmit="handleEventEmit" ref="sonRef" msg="我是父組件傳遞給子組件的msg屬性..."/>
        <Son1/>
    </div>
</template>
<script>
    import Son from './Son'
    import Son1 from './Son1'

    export default {
        name: "Parent",
        components: {
            Son,
            Son1
        },
        mounted() {
        },
        methods: {
            handleEventEmit(params) {
                console.log('父組件監聽到子組件派發的數據 -->', params);
            }
        }
    }
</script>
<style scoped>
</style>

Son組件

<template>
    <div>
        <!-- 子組件綁定派發事件 -->
        <h3 @click="$emit('eventEmit','我是事件派發想要傳遞的數據123.')">我是son組件</h3>
        <button @click="sendMsg">給兄弟Son1組件打招呼</button>
    </div>
</template>
<script>
    export default {
        name: "Son",
        props: ['msg'],
        data() {
            return {
                sonData: '我是子組件data 的數據...'
            }
        },
        methods: {
            sendMsg(){
                /* 通過中間組件, 共同父組件來派發事件 */
                this.$parent.$emit('sayHiToSiblings','大哥你好,我是你兄弟...')
            }
        }
    }
</script>
<style scoped>
</style>

Son1組件

<template>
    <div>
        <h2>我是Son1組件</h2>
    </div>
</template>

<script>
    export default {
        name: "Son1",
        mounted() {
            /* 通過中間組件 共同父組件 監聽事件 */
            this.$parent.$on('sayHiToSiblings',(msg)=>{
                console.log('%c我是Son1組件, 我接收Son兄弟組件的數據--->','color:pink',msg);
            })
        }
    }
</script>
<style scoped>
</style>

2.2 $bus 事件總線的方式實現兄弟組件通信

其原理就是通過藉助第三方組件的方式實現通信的.

如果兩個組件之間沒有共同的直接父組件, 我們還可以通過事件總線的方式, 實現跨組件之間的數據通信.

事件總線的方式可以完成任意組件之間的通信.

事件總線通信方式的使用:

1. // 在 main.js 中, 手動在 Vue 的原型上添加一個事件總線
	 Vue.prototype.$bus = new Vue()

	// 通過事件總線的 $on 方法,綁定一個方法
// 第一個參數: 事件名字
// 第二個參數: 需要處理的響應函數
this.$bus.$on('toggleTodo',(todo) => {
this.toggleTodo(todo)
})

2. // 在其他需要該方法的組件裏通過 $emit() 觸發該事件, 傳入參數
	// 第一個參數: 對應事件名字
// 第二個參數: 傳給回調函數的  實參
	this.$bus.$emit('toggleTodo',this.todoItem)

案例代碼如下:

main.js

import Vue from "vue";
import App from "./App.vue";

Vue.config.productionTip = false;

// 創建一個第三方實例掛到Vue原型, 用來實現事件總線通信
Vue.prototype.$bus = new Vue();

new Vue({
    render: h => h(App)
}).$mount("#app");

Son組件:

<template>
    <div>
        <h3>我是son組件</h3>
        <p>{{msg}}</p>
    </div>
</template>
<script>
    export default {
        name: "Son",
        data() {
            return {
                msg: ''
            }
        },
        mounted() {
            /* 在組件掛載完的時候完成監聽事件 */
            this.$bus.$on('siblingContact', (msg) => {
                console.log(msg);
                this.msg = msg
            })
        }
    }
</script>
<style scoped>
</style>

Son1 組件

<template>
    <div>
        <h2>我是Son1組件</h2>
        <button @click="handleClick">Son1組件點擊, 觸發Son組件傳遞過來的方法 </button>
    </div>
</template>

<script>
    export default {
        name: "Son1",
        methods:{
            handleClick(){
                // 觸發點擊事件的時候, 完成分發事件
                this.$bus.$emit('siblingContact','Hi,我是Son1, 我是你的兄弟啊...')
            }
        }
    }
</script>
<style scoped>
</style>

2.3 通過 PubSub.js 實現任意組件間通信

通過第三方的 Js庫, 可以實現任意組件之間的數據通信.

PubSub的使用

消息的 訂閱與發佈 就好比 事件的綁定和 觸發事件

**特點:**PubSub 消息訂閱與發佈這種方式實現通信可以實現任意組件之間的通信.

1. 安裝pubsub-js
		npm install pubsub-js

2. 在需要 消息訂閱與發佈的文件中, 首先引入 pubsub-js
		import PubSub from 'pubsub-js'   // 注意 pubsub引入的時候, 完整的是 pubsub-js

	// 訂閱消息, 傳入一個 事件名字, 一個回調函數.  訂閱事件就相當於定義的綁定事件
		PubSub.subscribe('MY TOPIC', ()=>{});

	//  發佈消息, 傳入一個與訂閱消息相同的 事件名字, 和 數據
// 發佈消息相當於 觸發函數, (給定義的函數傳遞過去參數數據)
		PubSub.publish('MY TOPIC', 'hello world!');

對 pubsub 消息訂閱機制的理解

#3. 對 pubsub 事件訂閱與發佈的理解
	// 事件的訂閱與發佈可以類比傳統的  給元素綁定事件 和 添加響應函數來理解
/**
 * 1. 在傳統的 添加綁定事件時有兩步
 *    >1. 給元素添加綁定事件函數, 函數傳入參數.
 *    >2. 給綁定的事件添加響應函數. (注意: 有函數)
 * 
 * 2. 在消息的訂閱與發佈中
 *    >1. 發佈消息(傳入參數)   ----> 相當於綁定事件
 *    >2. 訂閱消息('',fn)   ----> 相當於添加響應函數
 *        因爲訂閱消息中需要兩個參數, 第二個參數爲回調函數, 
 *        回調函數 就相當於我們所說的 事件的響應函數,也就是具體處理邏輯的函數
*/

3.0 祖孫組件或嵌套組件之間通信

3.1 provide/inject 實現嵌套組件通信

注意: 通過provideinject 方式實現的嵌套組件之間傳遞的數據, 不是響應式的.

  • 類型:

    provide: Object | ()=> Object

    inject: Array<string> | {[key:string]:string | symbol | Object}

  • 詳細

    provide 和 inject 主要在開發高階插件/組件庫時使用。並不推薦用於普通應用程序代碼中。
    

    provide 選項應該是一個對象或返回一個對象的函數。該對象包含可注入其子孫的 property。在該對象中你可以使用 ES2015 Symbols 作爲 key,但是隻在原生支持 SymbolReflect.ownKeys 的環境下可工作。

    inject 選項應該是:

    • 一個字符串數組,或
    • 一個對象,對象的 key 是本地的綁定名,value 是:
      • 在可用的注入內容中搜索用的 key (字符串或 Symbol),或
      • 一個對象,該對象的:
        • from property 是在可用的注入內容中搜索用的 key (字符串或 Symbol)
        • default property 是降級情況下使用的 value

案例代碼如下:

Parent組件:

<template>
    <div>
        <h1 style="color: pink">我是parent組件, 下面是Son組件</h1>
        <button @click="handleClick">點擊修改注入的數據</button>
        <Son/>
    </div>
</template>
<script>
    import Son from './Son'

    export default {
        name: "Parent",
        data() {
            return {
                msg: '我是給後代組件注入的數據'
            }
        },
        provide() {
            return {
                msg: this.msg
            }
        },
        components: {
            Son,
        },
        methods: {
            handleClick() {
                console.log('修改前 的祖先組件 msg數據 --->> ', this.msg);
                this.msg = '我修改了祖先組件想要注入給後代組件的數據...'
                console.log('修改後的祖先組件 msg數據 --->> ', this.msg);
            }
        },
        mounted() {
        },
    }
</script>
<style scoped>
</style>

Son組件:

<template>
    <div>
        <h3>我是son組件</h3>
        <GrandSon/>
    </div>
</template>
<script>
    import GrandSon from './GrandSon'

    export default {
        name: "Son",
        props: ['msg'],
        components: {GrandSon},
        data() {
            return {
                sonData: '我是子組件data 的數據...'
            }
        },
        methods: {}
    }
</script>
<style scoped>
</style>

GrandSon組件:

<template>
    <div>
        <h2>我是GrandSon組件</h2>
        <p>{{msg}}</p>
    </div>
</template>

<script>
    export default {
        name: "Son1",
        inject:['msg'],
        mounted() {
            /* 通過中間組件 共同父組件 監聽事件 */
            this.$parent.$on('sayHiToSiblings', (msg) => {
                // 由此可見,祖先組件點擊按鈕, 修改數據後, 此處數據並沒有修改, 所以數據是非響應式的
                console.log('%c我是Son1組件, 我接收Son兄弟組件的數據--->', 'color:pink', msg);
            })
        }
    }
</script>
<style scoped>
</style>

4.0 插槽的方式實現通信

插槽常用語內容分發. 原理就是佔位符的一個運用

插槽通信的方式後續會詳細介紹.

4.1 普通插槽

4.2 具名插槽

4.3 作用域插槽

總結:

交流學習添加微信(備註技術交流學習): Gene199302
在這裏插入圖片描述

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