vue 解決兄弟組件、跨組件深層次的通信操作
兄弟組件之間的通信同樣是在項目中經常會遇到的組件間的通信問題之一, 這種問題的最根本方法就是: 把兄弟組件內部的變量提升到一個中央倉庫。
借助父級組件鏈式交互
使子組件1 通過 $emit 通知父級, 父級再通過響應 子組件1 的事件去觸發子組件2的事件,這樣的鏈式操作,在子組件不多的時候,但是一個不錯的解決方法
子組件1
<template> <div> <p @click='$emit(’fromFirst’,’來自A組件’)'>first組件</p> </div></template><script> export default { name: ’first’ }</script>
子組件2
<template> 子組件2 <div>{{secondInfo}}</div></template><script>export default { name: ’second’, data() { return { this.secondInfo: null } }, created(){ this.$on(’fromFather’, (info) => { this.secondInfo = info }) }}</script>
父組件
<template> <first @fromFirst=’handleFromFirst’ /> <second ref=’second’ /> </template><script>import First from ’./first’import Scond from ’./second’export default { components: {First, Second}, data() { return { this.secondInfo: null } }, methods:{ handleFromFirst(val) { let second = this.$refs.second second.$emit(’fromFather’, val) } }}</script>
子組件1 觸發父組件的 fromFirst 事件, 在事件中又觸發了子組件2的 fromFather事件,并將從子組件1 傳遞過來的參數傳遞給了該事件, 當子組件2 執行該事件的時候,將內部的 secondInfo 改變。這就實現了一個兄弟組件的交互。
這個方式在 react 里面同樣也是適用的, 但是如果父組件內包含了多個子組件并包含了復雜的邏輯, 有沒有更好的方式來解決這種方式呢。
大部分第一個想到的是 vuex, 當然這在一個業務邏輯、數據復雜的項目中是一個很好的解決方法, 但是想象我們要編寫一個通用組件,這個組件可能被用到不同的項目中來, 如果使用 vuex 這就要求每一個使用這個組件的項目中都要使用 vuex, 這顯然是不好的。
借助中間文件,充當中央倉庫
還好 ES6 的模塊機制天然就支持建立一個中央倉庫, 當 A 文件使用 import value from ’./b.js’ 來引用 B 文件里面的 value 的時候, 這時就會賦值給 A 文件一個 B 文件的 value 的 只讀引用, 當 B 文件里面的 value 的值發生變化的時候, A 文件里面的 value 也會跟著改變。
// lib.jsexport let counter = 3;export function incCounter() {counter++;}// main.jsimport { counter, incCounter } from ’./lib’;console.log(counter); // 3incCounter();console.log(counter); // 4
定義一個額外的實例進行一個事件的中轉,對于ES6 模塊的運行機制已經有了一個講解,當模塊內部發生變化的時候,引入模塊的部分同樣會發生變化,當又一個額外的實例對加載機制進行引入進行emit與emit與emit與on進行綁定通信,能輕而易舉解決問題,通過b->a->c的模式直接過渡。
解決 vue 兄弟組件之間的通信我們同樣也可以使用中央倉庫的方式來實現。
// store.js 作為中央倉庫import Vue from ’vue’export default new Vue()
通過 new 一個 vue 的實例當作兄弟組件交互的中央倉庫。
父級組件
<template> <first/> <second/> </template><script>import First from ’./first’import Scond from ’./second’export default { components: {First, Second}}</script>
父組件只是引入子組件, 不再作為中央倉庫來過渡交互。
子組件1
<template> <div @click=’hanleClick’>子組件1</div></template><script>import Store from ’./store’export default { name: ’first’, methods: { handleClick() { Store.$emit(’fromFirst’, ’來自子組件1的傳值’) } }}</script>
因為我們的目的就是把 Store 作為一個中央倉庫,這里我們把 fromFirst 事件添加到了 Store 上面而不是當前組件 this 上。
子組件2
<template> 子組件2 <div>{{secondInfo}}</div></template><script>import Store from ’./store’export default { name: ’second’, data() { return { this.secondInfo: null } }, created(){ Store.$on(’fromFirst’, (info) => { this.secondInfo = info }) }}</script>
子組件2 里面同樣也是使用 Store 實例來監聽 fromFirst 事件, 因為子組件1和子組件2里面添加事件和監聽事件的是同一個實例,根據我們在上文中分析的 ES6 中的情況, 當 Store 添加了 fromFirst 這個時間之后, Store實例的 $on 就可以監聽到這個事件并執行回調。
跨組件深層次交互
上面講的組件之間的關系是這樣的:
我們可以實現 子組件之間的交互, 但是如果我們遇到這種情況呢?
孫組件需要跟子組件3 進行交互,還是使用上述的方法可以做到嗎? 答案是肯定的,只要能夠使用同一個中央倉庫,那么不管什么層級的組件復雜度,都是可以實現兩者的交互的。
補充知識:Vue組件跨層級通信
正常組件間通信
父->子組件 是通過屬性傳遞
子->父組件 是通過this.$emit()傳遞
this.$emit()返回的是this,如果需要一些值 可使用callback方式傳遞
provide 和 inject
這對選項需要一起使用,以允許一個祖先組件向其所有子孫后代注入一個依賴,
不論組件層次有多深,并在起上下游關系成立的時間里始終生效。
provide 和 inject 綁定并不是可響應的。這是刻意為之的。
然而,如果你傳入了一個可監聽的對象,那么其對象的屬性還是可響應的。
provide提供數據,多層子組件 向上層尋找,只要找到 就不在向上層尋找了.
inject 向子組件注入數據
使用方式
第一種方式(傳遞對象,使用字符串數組接收)
// 父級組件提供 ’foo’var Provider = { provide: { foo: ’bar’ }, // ...}// 子組件注入 ’foo’var Child = { inject: [’foo’], created () { console.log(this.foo) // => 'bar' } // ...}
第二種方式(傳遞返回對象的函數, 使用對象接收)
provide() { return { // 2.6.0 版本之前 通常傳遞this. 但這樣的話 會傳遞很多用不到的屬性 theme: { color: ’xxx’ //如果傳入可響應的數據,這里的屬性還是可響應的 } };}inject: { //這里可以換成其它名字 theme: { from: 'theme', // 數據來源 default: () => ({}) //降級情況下使用的 value //可以是 普通值 //可以是 對非原始值使用一個工廠方法 }}//正常子組件this.theme //即可訪問//子組件是函數式組件的使用方式injections.theme.color
Vue.observable( object )
讓一個對象可響應。Vue 內部會用它來處理 data 函數返回的對象。
可以作為最小化的跨組件狀態存儲器,用于簡單的場景
提供數據可改為
provide() { //這時提供的theme 則為可響應的數據 this.theme = Vue.observable({ color: 'blue' }); return { theme: this.theme };},
以上這篇vue 解決兄弟組件、跨組件深層次的通信操作就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持好吧啦網。
相關文章:
