摘要:使,最主要的的是跨組件通信全局數據維護。這兩種法旦發出事件后,任何組件都是可以接收到的,就近原則,且會在第次接收到后停冒泡,除返回。并且和也沒有解決兄弟組件間的通信問題。
Vue的組件是其非常重要的系統,組件之間的通信也是開發中不可避免的需求
一般來說Vue組件是以下幾種關系
A組件和B組件、B組件和C組件、B組件和D組件是父子關系,C組件和D組件是兄弟關系,A組件和C/D組件是隔代關系。
本文闡述了幾種常用的通信方式和使用場景
props&&emit父組件通過 props 傳遞數據給子組件,子組件通過 emit 發送事件傳遞數據給父組件
這種父子通信方式也就是典型的單向數據流,父組件通過 props 傳遞數據,子組件不能直接修改 props , 而是必須通過發送事件的方式告知父組件修改數據。
// component-a// component-b {{title}}
優點:易于使用,結構清晰
缺點:只能用于父子組件通信
ref&&$parent / $children這兩種都是直接得到組件實例,使?后可以直接調?組件的?法或訪問數據
ref:給元素或組件注冊引?信息
$parent/$children:訪問父/子組件
ref// component-a$parent / $children
$parent和$children都是基于當前上下文訪問父組件和子組件
// component-a// component-b
ref和$parent/$children的優缺點和props&&emit相同,弊端都是無法在跨級和兄弟間通信
provide/injectref和$parent/$children在跨級通信中有一定的弊端。
Vue.js 2.2.0 版本后新增 provide / inject API
vue文檔
這對選項需要?起使?,以允許?個祖先組件向其所有?孫后代注??個依賴,不論組件層次有多深,并在起上下游關系成?的時間?始終?效
provide 選項應該是一個對象或返回一個對象的函數。該對象包含可注入其子孫的屬性。
inject 選項應該是:
一個字符串數組
一個對象,對象的 key 是本地的綁定名,value 是:
在可用的注入內容中搜索用的 key (字符串或 Symbol),或
一個對象,該對象的:
from 屬性是在可用的注入內容中搜索用的 key (字符串或 Symbol)
default 屬性是降級情況下使用的 value
provide 和 inject 綁定并不是可響應的。這是刻意為之的。然而,如果你傳入了一個可監聽的對象,那么其對象的屬性還是可響應的。
// 父級組件提供 "foo" var Provider = { provide: { foo: "bar" }, // ... } // 子組件注入 "foo" var Child = { inject: ["foo"], created () { console.log(this.foo) // => "bar" } // ... }模擬Vuex
在做 Vue ?型項?時,可以使? Vuex 做狀態管理。使用 provide / inject,可以模擬 達到 Vuex 的效果 。
使? Vuex,最主要的?的是跨組件通信、全局數據維護。?如?戶的登錄信息維護、通知信息維護等全局的狀態和數據
通常vue應用都有一個根根組件app.vue,可以?來存儲所有需要的全局數據和狀態,methods 等。項目中所有的組件其父組件都是app,通過provide將app實例暴露對外提供
接下來任何組件只要通過 inject 注? app.vue 的 app 的話,都可以直接通過this.app.xxx 來訪問 app.vue 的 data、computed、methods 等內容
例如通過這個特性保存登錄信息
export default { provide() { return { app: this }; }, data() { return { userInfo: null }; }, methods: { getUserInfo() { // 這?通過 ajax 獲取?戶信息后,賦值給this.userInfo; $.ajax("/user", data => { this.userInfo = data; }); } }, mounted() { this.getUserInfo(); } };
之后在任何??或組件,只要通過 inject 注? app 后,就可以直接訪問 userInfo 的數據了
{{ app.userInfo }}
優點:
跨級注入
所有子組件都可獲取到注入的信息
缺點:
注入的數據非響應式
VuexVuex 是一個專為 Vue.js 應用程序開發的狀態管理模式。當需要開發開發大型單頁應用(SPA),就應該考慮使用Vuex了,它能把組件的共享狀態抽取出來,當做一個全局單例模式進行管理。這樣不管你在何處改變狀態,都會通知使用該狀態的組件做出相應修改。
Vuex官方文檔已經給出了詳細的使用方式
優點:
官方集成管理庫,可以處理各種場景的通信和狀態管理
缺點:
需要額外引入管理庫
Bus如果不是大型項目,狀態管理不復雜,數據量不是很大,沒有必要使用Vuex
可以使用一個空的vue實例作為事件總線中間件Bus處理組件間的通信
首先在全局定義bus
let bus = new Vue(); var eventBus = { install(Vue, options) { Vue.prototype.$bus = bus; } }; Vue.use(eventBus);
然后就可以在組件中使用$on,$emit,off來監聽,分發和銷毀組件
分發組件
// component-c
監聽組件
// component-d
最好在組件銷毀之前清除監聽事件
優點:
使用簡單,不需要額外支持
可以實現跨級和兄弟間通信
缺點:
需要在組件銷毀時,手動清除事件監聽
事件過多時比較混亂
dispatch/broadcast$dispatch 和 $broadcast 是Vue1.x中提供的API,前者?于向上級派發事件,只要是它的?級(?級或多級以上),都可以在組件內通過 $on 監聽到,后者相反,是由上級向下級?播事件
// 子組件 vm.$dispatch(eventName,params) // 父組件 vm.$on(eventName , (params) => { console.log(params); });
$broadcast 類似,只不過?向相反。這兩種?法?旦發出事件后,任何組件都是可以接收到的,就近原則,?且會在第?次接收到后停?冒泡,除?返回 true 。
這2個方法在已經被棄用,Vue官方給出的解釋是:
因為基于組件樹結構的事件流方式實在是讓人難以理解,并且在組件結構擴展的過程中會變得越來越脆弱。這種事件方式確實不太好,我們也不希望在以后讓開發者們太痛苦。并且$dispatch 和 $broadcast 也沒有解決兄弟組件間的通信問題。
雖然在開發中,沒有Vuex這樣的專業狀態管理工具方便好用,但是在獨立組件庫和一些特殊場景中,也是非常好用的一種傳遞方式。
模擬dispatch/broadcast自行模擬dispatch/broadcast無法達到與原方法一模一樣的效果,但是基本功能都是可以實現的,解決組件之間的通信問題
方法有功能有向上/下找到對應的組件,觸發指定事件并傳遞數據,其下/上級組件已經通過$on監聽了該事件。
首先需要正確地向上或向下找到對應的組件實例,并在它上?觸發?法。
function broadcast(componentName, eventName, params) { this.$children.forEach(child => { const name = child.$options.name; if (name === componentName) { child.$emit.apply(child, [eventName].concat(params)); } else { broadcast.apply(child, [componentName, eventName].concat([params])); } }); } export default { methods: { dispatch(componentName, eventName, params) { let parent = this.$parent || this.$root; let name = parent.$options.name; while (parent && (!name || name !== componentName)) { parent = parent.$parent; if (parent) { name = parent.$options.name; } } if (parent) { parent.$emit.apply(parent, [eventName].concat(params)); } }, broadcast(componentName, eventName, params) { broadcast.call(this, componentName, eventName, params); } } };
這兩個?法都接收了三個參數,第?個是組件的 name 值,?于向上或向下遞歸遍歷來尋找對應的組件,第?個和第三個就是上?分析的?定義事件名稱和要傳遞的數據。
在 dispatch ?,通過 while 語句,不斷向上遍歷更新當前組件(即上下?為當前調?該?法的組件)的?組件實例(變量 parent 即為?組件實例),直到匹配到定義的 componentName 與某個上級組件的 name 選項?致時,結束循環,并在找到的組件實例上,調? $emit ?法來觸發?定義事件 eventName 。 broadcast ?法與之類似,只不過是向下遍歷尋找
優點:
使用簡單
可以實現跨級通信
缺點:
原生支持已經廢除,需要自行實現
findComponents系列上述介紹的各種通信方法都有各自的局限性,我們可以實現一個 findComponents 系列的方法,可以實現
向上找到最近的指定組件
向上找到所有的指定組件
向下找到最近的指定組件
向下找到所有指定的組件
找到指定組件的兄弟組件
5個方法都是通過遞歸和遍歷,通過組件name選項匹配到指定組件返回
向上找到最近的指定組件function findComponentUpward(context, componentName) { let parent = context.$parent; // 獲取父級組件 let name = parent.$options.name; // 獲取父級組件名稱 // 如果父級存在 且 父級組件 沒有name 或 name與要尋找的組件名不一致,重置parent和name,再逐級尋找 while (parent && (!name || [componentName].indexOf(name) < 0)) { parent = parent.$parent; if (parent) name = parent.$options.name; } // 逐級查找父級組件名和傳參名是否一致,返回找到的parent return parent; }
findComponentUpward 接收兩個參數,第?個是當前上下?,即你要基于哪個組件來向上尋找,?般都是基于當前的組件,也就是傳? this;第?個參數是要找的組件的 name 。
dispatch是通過觸發和監聽事件來完成事件交互,findComponentUpward 會直接拿到組件的實例
function findComponentsUpward(context, componentName) { let parents = []; // 收集指定組件 const parent = context.$parent; if (parent) { if (parent.$options.name === componentName) parents.push(parent); return parents.concat(findComponentsUpward(parent, // 遞歸逐級向上尋找 componentName)); } else { return []; } }
findComponentsUpward會返回的是?個數組,包含了所有找到的組件實例
findComponentsUpward 的使?場景較少
function findComponentDownward(context, componentName) { const childrens = context.$children; let children = null; if (childrens.length) { for (const child of childrens) { const name = child.$options.name; if (name === componentName) { children = child; break; } else { children = findComponentDownward(child, componentName); if (children) break; } } } return children; }
context.$children 得到的是當前組件的全部?組件,所以需要遍歷?遍,找到有沒有匹配到的組件 name,如果沒找到,繼續遞歸找每個 $children 的 $children,直到找到最近的?個為?
向下找到所有指定的組件function findComponentsDownward(context, componentName) { return context.$children.reduce((components, child) => { if (child.$options.name === componentName) components.push(child); const foundChilds = findComponentsDownward(child, componentName); return components.concat(foundChilds); }, []); }
使? reduce 做累加器,并?遞歸將找到的組件合并為?個數組并返回
找到指定組件的兄弟組件function findBrothersComponents(context, componentName, exceptMe = true) { let res = context.$parent.$children.filter(item => { return item.$options.name === componentName; }); let index = res.findIndex(item => item._uid === context._uid); if (exceptMe) res.splice(index, 1); return res; }
findBrothersComponents 多了?個參數 exceptMe ,是否把本身除外,默認是 true 。尋找兄弟組件的?法,是先獲取 context.$parent.$children,也就是?組件的全部?組件,這??當前包含了本身,所有也會有第三個參數exceptMe。Vue.js 在渲染組件時,都會給每個組件加?個內置的屬性 _uid,這個 _uid 是不會重復的,借此我們可以從?系列兄弟組件中把??排除掉。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/103608.html
摘要:本身提供哪幾種通信方式首先靈感源于,支持雙向綁定,本質還是單向數據流。跟一樣,組件間最基本的數據流是通過向子組件傳遞數據。但是在卻很少使用,因為組件可以自定義事件,即后面的組件間通信方式其實就是訂閱發布模式。 例子是在 jsrun.net 平臺編寫,不支持移動端平臺,所以本文建議在 PC 端進行閱讀。 Vue 是數據驅動的視圖框架,那么組件間的數據通信是必然的事情,那么組件間如何進行數...
摘要:一父組件通過的方式向子組件傳遞數據,而通過子組件可以向父組件通信。而且只讀,不可被修改,所有修改都會失效并警告。 之前寫了一篇關于vue面試總結的文章, 有不少網友提出組件之間通信方式還有很多, 這篇文章便是專門總結組件之間通信的 vue是數據驅動視圖更新的框架, 所以對于vue來說組件間的數據通信非常重要,那么組件之間如何進行數據通信的呢?首先我們需要知道在vue中組件之間存在什么樣...
摘要:組件基礎與通信一腳手架簡介與安裝之前安裝的是模塊,之后安裝的是模塊。如果是三級組件通信,該如何處理比如父組件與孫子組件通信。和,提供和注入實現祖先組件和后代組件之間通信。 Vue組件基礎與通信 一、vue cli腳手架 ① vue cli 簡介與安裝 vue cli 3.0之前安裝的是vue-cli模塊,vue cli 3.0之后安裝的是@vue/cli模塊。如果已經全局安裝了舊版本的...
摘要:雖然和都可以獲取組件實例,但是它們無法在跨級或兄弟間通信,這是它們的缺點。也就是在父組件中提供一個值,并且在需要使用的子孫組件中注入改值,即不僅僅是,只要是的子組件,無論隔多少代,都可以通過這個的方式注入。通過混入組件,實現組件間的通信。 寫在前面 vue 的組件化應該是其最核心的思想了,無論是一個大的頁面還是一個小的按鈕,都可以被稱之為組件。基于 Vue 的開發,就是在寫一個個組件,...
摘要:整理種組件通信方式重點是梳理了前兩個父子組件通信和通信我覺得文檔里的說明還是有一些簡易我自己第一遍是沒看明白。第四種通信方式利用比較復雜可以單獨寫一篇 整理4種Vue組件通信方式 重點是梳理了前兩個,父子組件通信和eventBus通信,我覺得Vue文檔里的說明還是有一些簡易,我自己第一遍是沒看明白。 父子組件的通信 非父子組件的eventBus通信 利用本地緩存實現組件通信 Vuex...
總結一下對vue組件通信的理解和使用。 一、組件目錄結構 父組件:app.vue 子組件:page1.vue 子組件:page2.vue 父組件 app.vue 請輸入單價: import Page1 from ./components/page1; import Page2 from ./components/page2; export de...
閱讀 3094·2021-10-13 09:40
閱讀 3945·2021-09-22 15:51
閱讀 1492·2021-09-22 15:48
閱讀 1060·2021-09-06 15:00
閱讀 1789·2019-08-30 15:43
閱讀 2354·2019-08-29 18:35
閱讀 1666·2019-08-29 16:18
閱讀 3611·2019-08-29 12:49