vue 修改div寬度_Vue 組件通信方式及其應用場景總結(1.5W字)

前言

相信實際項目中用過vue的同學,一定對vue中父子組件之間的通信并不陌生,vue中采用良好的數據通訊方式,避免組件通信帶來的困擾。今天筆者和大家一起分享vue父子組件之間的通信方式,優缺點,及其實際工作中的應用場景

首先我們帶著這些問題去思考

1 vue中到底有多少種父子組件通信方式?

2 vue中那種父子組件最佳通信方式是什么?

3 vue中每個通信方式應用場景是什么?

一 prop

1 基本用法

prop通信方式大家最常見的,也是最常用的父子組件通信類型,我們可以直接在標簽里面給子組件綁定屬性和方法,對于屬性我們可以直接通過子組件聲明的prop拿到,對于父元素的方法,我們可以通過?this.$emit觸發

我們先簡單寫一個props父子組件通信的場景

父組件

<template>
<div class="father" >
<input v-model="mes" /> <button @click="send" >對子組件說button>
<div>子組件對我說:{{ sonMes }}div>
<son :fatherMes="sendSonMes" @sonSay="sonSay" />
div>
template>
<script>import son from './son'export default {name:'father',components:{
son /* 子組件 */
},data(){return {mes:'',sendSonMes:'', /* 來自子組件的信息 */sonMes:'' /* 發送給子組件的信息 */
}
},methods:{/* 傳遞給子組件 */send(){this.sendSonMes = this.mes
},/* 接受子組件信息 */ sonSay(value){this.sonMes = value
},
},
}script>

我們這里只需要將給子組件的數據fatherMes和提供給子組件的方法?sonSay?通過標簽方式傳遞給子組件。

子組件

<template>
<div class="son" >
<div> 父組件對我說:{{ fatherMes }} div>
<input v-model="mes" /> <button @click="send" >對父組件說button>
div>
template>
<script>export default {name:'son',props:{fatherMes:{type:String,default:''
}
},data(){return {mes:''
}
},methods:{send(){this.$emit('sonSay',this.mes)
}
},
}script>>

子組件通過props來定義接受父組件傳遞過來的信息,我們就可以直接通過this獲取到,對于父組件傳遞的事件,我們可以通過this.$emit來觸發事件。

區別react的props

這里和reactprops有點區別,react組件更新來源于props更新和自身state改變,當props改變,會默認更新組件。而在Vue中,如果我們對父組件傳過來的新的props沒有做依賴收集(template模版收集,computed計算屬性收集),組件是不會觸動更新的。

效果

a7111b507a56f9adf3d034998accd4e0.gif

數據格式化

如果我們想對props數據進行數據格式化,那么用computed接受props并格式化想要的數據類型。

<div class="son" >
<div> 父組件對我說:{{ computedFatherMes }} div>
<input v-model="mes" /> <button @click="send" >對父組件說button>
div>
export default {
name:'son',
props:{
fatherMes:{
type:String,
default:''
}
},
computed:{
computedFatherMes(){
return this.fatherMes + '??'
}
},

}

824fa92e0a88a2fb6c2046caf90877e6.png

數據監聽

當我們根據props改變不想更新視圖,或者不想立即更新視圖,那么可以用watch來監聽來自父組件的props的變化。

watch:{
fatherMes(newVaule){
console.log( newVaule)
}
},

2優點

props傳遞數據優點是顯而易見的,靈活簡單,可以對props數據進行計算屬性,數據監聽等處理。父子組件通信靈活方便。這里可能單單僅限父子一層。

3缺點

1 props篡改

我們在子組件中使用父組件props的時候,如果涉及一些變量賦值,修改等操作,props被莫名其妙的修改了,連同父組件的數據也被篡改了,有的同學可能會很疑惑,父元素的props不是不能修改么,這里怎么改變了呢,vueprops到底能不能改變?,至于這個問題,不能直接給出答案,如果props是基礎數據類型,當我們改變的時候,就會曝出錯誤。我們一起看一個例子。

a9d72c8681fd33ce000d66c345b1c8af.png

父組件

<template>
<div>
<div>父組件div>
<son :fData="sonProps" />
div>
template>
<script>import son from './sTampering'export default {name:'father',components:{
son
},data(){return {sonProps:''
}
},
}script>

子組件

<template>
<button >改變父組件propsbutton>
template>

<script>export default {name:'son',props:{fData:{required:true
}
},methods:{changFatherProps(){this.fData = 'hello ,father'
}
}
}script>

當我們直接點擊button 會拋出以下警。

4a603cb3749e5a3e3e776fc227b06399.png

但是當我們傳過來的是一個引用數據類型,并且修改數據下某一個屬性的時候。

父組件

data(){
return {
sonProps:{
a:1,
b:2
}
}
},

子組件

changFatherProps(){
this.fData.a = 'hello,world'
}

當點擊按鈕發現并沒有報錯。

于是我們打印父組件的sonprops數據:

36a234f81ab18e0454e6a16bbe4bada1.png

我們發現父組件的data數據已經被子組件篡改。于是我們總結出一個結論,子組件雖然不能直接對父組件prop進行重新賦值,但是當父組件是引用類型的時候,子組件可以修改父組件的props下面的屬性。這就是一個很尷尬的事情,如果我們設計的初衷就是父組件數據也同時被修改,這個結果是可以接受的,但是當我們不希望父組件那份數據源有任何變化的時候,這就是一個嚴重的邏輯bug。所以這就是props通訊的風險項之一。

2 跨層級通信,兄弟組件通訊困難

對于父組件-子組件-子組件的子組件這種跨層級的通信,顯然需要我們一層一層的prop綁定屬性和方法,如果遇到更復雜的情況,實現起來比較困難。

df050862de54d7bba12a596ef9797609.png

對于兄弟組件之間的通訊,props需要通過父組件作為橋梁,實現子組件-> 父組件 -> 子組件通信模式,如果想要通過父組件做媒介,那么必定會造成父組件重新渲染,為了實現兄弟組件通信付出的代價比較大。d222f49ac31991a879ff0b52f7cbcfa0.png

4 應用場景

props的應用場景很簡單,就是正常不是嵌套很深的父子組件通信,和關系不是很復雜的兄弟組件組件通信。

二 this.$xxx

通過this下面的數據直接獲取vue實例這種方法比較暴力,因為我們所謂的組件,最終都會是一個對象,存放組件的各種信息,組件和組件通過this.$childrenthis.$parent指針關聯起來。因為在項目中只有一個root根組件,理論上,我們可以找到通過this.$children?this.$parent來訪問頁面上的任何一個組件 ,但是實際上如何精確匹配到目標組件,確是一個無比棘手的問題。

1 基本用法

父組件

<template>
<div class="father" >
<input v-model="mes" /> <button @click="send" >對子組件說button>
<son2 v-if="false" />
<div>子組件對我說:{{ sonMes }}div>
<son />
div>
template>
<script>import son from './son'import son2 from './son2'export default {name:'father',components:{
son ,/* 子組件 */
son2
},data(){return {mes:'',sendSonMes:'', /* 來自子組件的信息 */sonMes:'' /* 發送給子組件的信息 */
}
},methods:{/* 傳遞給子組件 */send(){/* 因為son組件是第一個有效組件所以直接去下標為0的組件 */const currentChildren = this.$children[0]
currentChildren.accept(this.mes)
},/* 接收子組件的信息 */accept(value){this.sonMes = value
}
},
}script>

子組件

<template>
<div class="son" >
<div> 父組件對我說:{{ fatherMes }} div>
<input v-model="mes" /> <button @click="send" >對父組件說button>
div>
template>
<script>export default {name:'son',data(){return {mes:'',fatherMes:''
}
},methods:{/* 接受父組件內容 */accept(value){this.fatherMes = value
},/* 向父組件發送信息 */send(){this.$parent.accept(this.mes)
},
},
}script>

效果

d7bb16a11b44a8406ceef5743411d474.gif

我們可以清楚看到,和props通信相比,this.$parentthis.$children顯得更加簡潔,無需再給子組件綁定事件和屬性,只需要在父組件和子組件聲明發送和接受數據的方法。就可以實現組件間的通信,看起來很是便捷,但是實際操作中會有很大的弊端,而且vue本身也不提倡這種通信方式。而且這種通信方式也有很多風險性,我們稍后會給予解釋。

2 優點

簡單,方便?this.$children,this.$parent?this.$refs?這種通信方式,更加的簡單直接獲取vue實例,對vue實例下的數據和方法直接獲取或者引用。

3 缺點

1 $this.children不可控性大,有一定風險

如上的例子,我們稍微對父組件加以改動,就會直接報錯。

之前的

 <son2 v-if="false" />

改成

<son2 v-if="true" />

ec6510b7ab72b8809928c2d3d1d67293.png

就會報如上錯誤,錯誤的原因很簡單,我們用?$children?的下標獲取,但是兄弟組件son2?v-if = true?之后,我們通過通過this.$children[0]?獲取的就是son2組件,son2沒有綁定方法,所以得出結論,對于v-if動態控制組件顯示隱藏的不建議用this.$children用法,取而代之的我們可以用ref獲取對應子組件的實例。

如上改成

<son ref="son" />

然后獲取:

const currentChildren = this.$refs.son

根本解決了問題。

2 不利于組件化

直接獲取組件實例這種方式,在一定程度上妨礙了組件化開發,組件化開發的過程中,那些方法提供給外部,那些方法是內部使用,在沒有提前商量的情況下,父子組件狀態不透明的情況下,一切都是未知的,所以不同開發人員在獲取組件下的方法時候,存在風險,提供的組件方法,屬性是否有一些內部耦合。組件開發思路初衷,也不是由組件外部來對內部作出一定改變,而往往是內部的改變,通知外部綁定的方法事件。反過來如果是子組件內部,主動向父組件傳遞一些信息,也不能確定父組件是否存在。

3 兄弟組件深層次嵌套組件通訊困難

和props方式一下,如果是兄弟直接組件的通信,需要通過父組件作為中間通訊的橋梁,而深層次的組件通訊,雖然不需要像props通訊那樣逐層綁定,但是有一點,需要逐漸向上層或下層獲取目標實例,如何能精準獲取這是一個非常頭疼的問題,而且每當深入一層,風險性和不確定性會逐級擴大。

4 應用場景

直接通過實例獲取的通信方式適合已知的,固定化的頁面結構,這種通訊方式,要求父子組件高度透明化,知己知彼,很明確父子組件有那些方法屬性,都是用來干什么。所以說這種方式更適合頁面組件,而不適合一些第三方組件庫,或者是公共組件。

三 provide inject

如果說vue中?provide?和?inject,我會首先聯想到reactcontext上下文,兩個作用在一定程度上可以說非常相似,在父組件上通過provide將方法,屬性,或者是自身實例暴露出去,子孫組件,插槽組件,甚至是子孫組件的插槽組件,通過inject把父輩provide引進來。提供給自己使用,很經典的應用?provide和?inject的案例就是?element-ui中?el-form和?el-form-item

我們先不妨帶著問題想象一個場景

<el-form  label-width="80px" :model="formData">
<el-form-item label="姓名">
<el-input v-model="formData.name">el-input>
el-form-item>
<el-form-item label="年齡">
<el-input v-model="formData.age">el-input>
el-form-item>
el-form>

我們可以看到?el-form?和?el-form-item不需要建立任何通信操作,那么el-formel-form-item?是如何聯系起來,并且共享狀態的呢?我們帶著疑問繼續往下看。

1 基本用法

普通方式

我們用父組件 -> 子組件 -> 孫組件 的案例

父組件

<template>
<div class="father" >
<div>子組件對我說:{{ sonMes }}div>
<div>孫組件對我說:{{ grandSonMes }}div>
<son />
div>
template>
<script>import son from './son'export default {name:'father',components:{
son /* 子組件 */
},provide(){return {/* 將自己暴露給子孫組件 ,這里聲明的名稱要于子組件引進的名稱保持一致 */father:this
}
},data(){return {grandSonMes:'', /* 來自子組件的信息 */sonMes:'' /* 發送給子組件的信息 */
}
},methods:{/* 接受孫組件信息 */grandSonSay(value){this.grandSonMes = value
},/* 接受子組件信息 */ sonSay(value){this.sonMes = value
},
},
}script>

這里我們通過provide把本身暴露出去。??????這里聲明的名稱要與子組件引進的名稱保持一致

子組件

<template>
<div class="son" >
<input v-model="mes" /> <button @click="send" >對父組件說button>
<grandSon />
div>
template>

<script>import grandSon from './grandSon'export default {/* 子組件 */name:'son',components:{
grandSon /* 孫組件 */
},data(){return {mes:''
}
},/* 引入父組件 */inject:['father'],methods:{send(){this.father.sonSay(this.mes)
}
},
}script>

子組件通過inject把父組件實例引進來,然后可以直接通過this.father可以直接獲取到父組件,并調用下面的sonSay方法。

孫組件

<template>
<div class="grandSon" >
<input v-model="mes" /> <button @click="send" >對爺爺組件說button>
div>
template>

<script>export default {/* 孫組件 */name:'grandSon',/* 引入爺爺組件 */inject:['father'],data(){return {mes:''
}
},methods:{send(){this.father.grandSonSay( this.mes )
}
}
}script>

孫組件沒有如何操作,引入的方法和子組件一致。

效果

6b8493cdc9a3f194304605178b040483.gif

2 插槽方式

provide , inject?同樣可以應用在插槽上,我們給父子組件稍微變動一下。

父組件

<template>
<div class="father" >
<div>子組件對我說:{{ sonMes }}div>
<div>孫組件對我說:{{ grandSonMes }}div>
<son >
<grandSon/>
son>
div>
template>
<script>import son from './slotSon'import grandSon from './grandSon' export default {name:'father',components:{
son, /* 子組件 */
grandSon /* 孫組件 */
},provide(){return {/* 將自己暴露給子孫組件 */father:this
}
},data(){return {grandSonMes:'', /* 來自子組件的信息 */sonMes:'' /* 發送給子組件的信息 */
}
},methods:{/* 接受孫組件信息 */grandSonSay(value){this.grandSonMes = value
},/* 接受子組件信息 */ sonSay(value){this.sonMes = value
},
},
}script>

子組件

<template>
<div class="son" >
<input v-model="mes" /> <button @click="send" >對父組件說button>
<slot />
div>
template>

達到了同樣的通信效果。實際這種插槽模式,所在都在父組件注冊的組件,最后孫組件也會綁定到子組件的children下面。和上述的情況差不多。

provied其他用法

provide不僅能把整個父組件全部暴露出去,也能根據需要只暴露一部分(一些父組件的屬性或者是父組件的方法),上述的例子中,在子孫組件中,只用到了父組件的方法,所以我們可以只提供兩個通信方法。但是這里注意的是,如果我們向外提供了方法,如果方法里面有操作this行為,需要綁定this

父組件

   provide(){
return {
/* 將通信方法暴露給子孫組件(注意綁定this) */
grandSonSay:this.grandSonSay.bind(this),
sonSay:this.sonSay.bind(this)
}
},
methods:{
/* 接受孫組件信息 */
grandSonSay(value){
this.grandSonMes = value
},
/* 接受子組件信息 */
sonSay(value){
this.sonMes = value
},
},

子組件

/* 引入父組件方法 */
inject:['sonSay'],
methods:{
send(){
this.sonSay(this.mes)
}
},

2 優點

ab01b085c3d593078658ee510cbaa122.png

1 組件通信不受到子組件層級的影響

provide inject用法 和?react.context非常相似,?provide相當于Context.Provider?,inject?相當于?Context.Consumer,讓父組件通信不受到組件深層次子孫組件的影響。

2 適用于插槽,嵌套插槽

provide inject?讓插槽嵌套的父子組件通信變得簡單,這就是剛開始我們說的,為什么?el-form?和?el-form-item能夠協調管理表單的狀態一樣。在element源碼中?el-form?就是將this本身provide出去的。

3 缺點

1 不適合兄弟通訊

provide-inject?協調作用就是獲取父級組件們提供的狀態,方法,屬性等,流向一直都是由父到子,provide提供內容不可能被兄弟組件獲取到的,所以兄弟組件的通信不肯能靠這種方式來完成。

2 父級組件無法主動通信

provide-inject更像父親掙錢給兒子花一樣,兒子可以從父親這里拿到提供的條件,但是父親卻無法向兒子索取任何東西。正如這個比方,父組件對子組件的狀態一無所知。也不能主動向子組件發起通信。

4 應用場景

provide-inject這種通信方式,更適合深層次的復雜的父子代通信,子孫組件可以共享父組件的狀態,還有一點就是適合el-form?el-form-item這種插槽類型的情景。

四 vuex

vuex算是vue中處理復雜的組件通信的最佳方案,畢竟是vuevuex一個娘胎里出來的。而且vuex底層也是用vue實現的。相信不少同學對vuex并不陌生。接下來我們開始介紹vuex。

ee033f12866135fa6ce11aedd27af0a2.png

1 基礎用法

vuex文件

import Vuex from 'vuex'
import Vue from 'vue'

Vue.use(Vuex)

export default new Vuex.Store({
state:{
fatherMes:'',
sonMes:'',
fatherMesAsync:''
},
mutations:{
sayFaher(state,value){
state.fatherMes = value
},
saySon(state,value){
state.sonMes = value
},
sayAsyncFather(state,value){
state.fatherMesAsync = value
}
},
actions:{
asyncSayFather({ commit },payload){
return new Promise((resolve)=>{
setTimeout(()=>{
resolve(payload)
},2000)
}).then(res=>{
commit('sayAsyncFather',res)
})
}
}
})

store文件中,我們聲明三個mutations?分別是向父組件通信saySon,父組件向子組件通信,同步方法sayFaher和異步方法sayAsyncFather?,actions中模擬了一個三秒后執行的異步任務asyncSayFather

main.js

import store from './components/vuex/store'

new Vue({
render: h => h(App),
store
}).$mount('#app')

main.js注入store

父組件

<template>
<div class="father" >
<input v-model="mes" /> <button @click="send" >同步:對子組件說button><br/>
<input v-model="asyncMes" /> <button @click="asyncSend" >異步:對子組件說button><br/>
<div>子組件對我說:{{ sonMes }}div>
<son />
div>
template>
<script>import son from './son'export default {/* 父組件 */name:'father',components:{
son ,/* 子組件 */
},data(){return {mes:'',asyncMes:''
}
},computed:{sonMes(){return this.$store.state.sonMes
}
},mounted(){console.log(this.$store)
},methods:{/* 觸發mutations,傳遞數據給子組件 */send(){this.$store.commit('sayFaher',this.mes)
},/* 觸發actions,傳遞數據給子組件 */asyncSend(){this.$store.dispatch('asyncSayFather',this.asyncMes)
}
},
}script>

父組件分別觸發同步異步方法,把信息發送給子組件。用computed來接受vuex中的state

子組件

<template>
<div class="son" >
<div> 父組件對我說:{{ fatherMes }} div>
<div> 父組件對我說(異步):{{ fatherMesAsync }} div>
<input v-model="mes" /> <button @click="send" >對父組件說button>
div>
template>
<script>export default {name:'son',data(){return {mes:'',
}
},computed:{/* 接受父組件同步消息 */fatherMes(){return this.$store.state.fatherMes
},/* 接受父組件異步消息 */fatherMesAsync(){return this.$store.state.fatherMesAsync
}
},methods:{/* 向父組件發送信息 */send(){this.$store.commit('saySon',this.mes)
},
},
}script>

子組件的方法和父組件保持一致。

效果

f89b4665f4cde5b562339a5b1a38d8bb.gif

2 優點

1 根本解決復雜組件的通信問題

vuex在一定程度上根本解決了vue復雜的組件通信情況,我們不再關心兩個毫無干系的兩個組件的通信問題。

2 支持異步組件通信

vuexactions允許我們做一些異步操作,然后通過commit可以把數據傳入對應的mutation,至于actions為什么可以執行異步,是因為里面底層通過Promise.resolve能夠獲取異步任務完成的狀態。

3 缺點

1 流程相比稍微復雜

vuex通信方式相比其他方式,比較復雜,而且如果不同的模塊,需要建立獨立的modules

4 應用場景

實際開發場景中,不會存在demo項目這樣簡單的通信,vuex的出現,就是解決這些比較復雜的組件通信場景。對于中大型項目,vuex是很不錯的狀態管理,數據通信方案。

五 事件總線一 EventBus

EventBus事件總線,?EventBus?所有事件統一調度,有一個統一管理事件中心,一個組件綁定事件,另一個組件觸發事件,所有的組件通信不再收到父子組件的限制,那個頁面需要數據,就綁定事件,然后由數據提供者觸發對應的事件來提供數據,這種通訊場景不僅僅應用在vue,而且也應用在react

EventBus?核心思想是事件的綁定和觸發,這一點和vue中?this.$emit?和?this.$on一樣,這個也是整個EventBus核心思想。接下來我們來重點解析這個流程。

1 基本用法

EventBus

export default class EventBus {
es = {}
/* 綁定事件 */
on(eventName, cb) {
if (!this.es[eventName]) {
this.es[eventName] = []
}
this.es[eventName].push({
cb
})
}
/* 觸發事件 */
emit(eventName, ...params) {
const listeners = this.es[eventName] || []
let l = listeners.length

for (let i = 0; i < l; i++) {
const { cb } = listeners[i]
cb.apply(this, params)
}
}
}

export default new EventBus()

這個就是一個簡單的事件總線,有on,emit兩個方法。

父組件

<template>
<div class="father" >
<input v-model="mes" /> <button @click="send" >對子組件說button>
<div>子組件對我說:{{ sonMes }}div>
<son />
<brotherSon />
div>
template>
<script>import son from './son'import brotherSon from './brother'import EventBus from './eventBus'export default {name:'father',components:{
son ,/* 子組件 */
brotherSon, /* 子組件 */
},data(){return {mes:'',sonMes:''/* 發送給子組件的信息 */
}
},mounted(){/* 綁定事件 */
EventBus.on('sonSay',this.sonSay)
},methods:{/* 傳遞給子組件 */send(){
EventBus.emit('fatherSay',this.mes)
},/* 接受子組件信息 */ sonSay(value){this.sonMes = value
},
},
}script>

我們在初始化的時候通過EventBuson方法綁定sonSay方法供給給子組件使用。向子組件傳遞信息的時候,通過emit觸發子組件的綁定方法,實現了父子通信。接下來我們看一下子組件。

子組件

<template>
<div class="son" >
<div> 父組件對我說:{{ fatherMes }} div>
<input v-model="mes" /> <button @click="send" >對父組件說button>
<div>
<input v-model="brotherMes" /> <button @click="sendBrother" >對兄弟組件說button>
div>
div>
template>
<script>import EventBus from './eventBus' export default {name:'son',data(){return {mes:'',brotherMes:'',fatherMes:''
}
},mounted(){/* 綁定事件 */
EventBus.on('fatherSay',this.fatherSay)
},methods:{/* 向父組件傳遞信息 */send(){
EventBus.emit('sonSay',this.mes)
},/* 向兄弟組件傳遞信息 */sendBrother(){
EventBus.emit('brotherSay',this.brotherMes)
},/* 父組件對我說 */fatherSay(value){this.fatherMes = value
}
},
}script>

和父組件的邏輯差不多,把需要接受數據的方法,通過EventBus綁定,通過觸發eventBus方法,來向外部傳遞信息。我們還模擬了兄弟之間通信的場景。我們建立一個兄弟組件。

<template>
<div class="son" > 兄弟組件對我說: {{ brotherMes }} div>
template>

<script>import EventBus from './eventBus'export default {/* */name:'brother',data(){return {brotherMes:''
}
},mounted(){/* 綁定事件給兄弟組件 */
EventBus.on('brotherSay',this.brotherSay)
},methods:{brotherSay(value){this.brotherMes = value
}
}
}script>

我們可以看到,兄弟組件處理邏輯和父子之間沒什么區別。

效果

3dacc154c6d6e7688c131b3f04ba5716.gif

2 優點

1 簡單靈活,父子兄弟通信不受限制。

eventBus的通信方式,相比之前的幾種比較簡單,而且不受到組件層級的影響,可以實現任意兩個組件的通信。需要數據就通過on綁定,傳遞數據就emit觸發。

2 通信方式不受框架影響

eventBus的通信方式,不只是vue可以用,react,小程序都可以使用這種通信方式,而且筆者感覺這種通信方式更適合小程序通信,至于為什么稍后會一一道來。

4 缺點

1 維護困難,容易引起連鎖問題

如果我們采用事件總線這種通信模式,因為所有事件是高度集中,統一管理的,中間如果有一個環節出現錯誤,就會造成牽一發動全身的災難.而且后期維護也是十分困難的。

2 需要謹小慎微的命令規范

現實的應用場景,要比demo場景復雜的多,實際場景會有無數對父子組件,無數對兄弟組件,我們不肯能每個事件都叫相同名字,所以eventBus綁定事件的命名要有嚴格的規范,不能起重復名字,也不能用錯名字。

3 不利于組件化開發

eventBus通信方式是無法進行有效的組件化開發的,假設一個場景,一個頁面上有多個公共組件,我們只要向其中的一個傳遞數據,但是每個公共組件都綁定了數據接受的方法。我們怎么樣做到把數據傳遞給需要的組件呢?

4 應用場景

1b02f5cb5f2fbfb629a61dcaccbac85a.png

實現總線這種方式更適合,微信小程序,和基于vue構建的小程序,至于為什么呢,因為我們都知道小程序采用雙線程模型(渲染層+邏輯層)(如下圖所示),渲染層作用就是小程序wxml渲染到我們的視線中,而邏輯層就是我們寫的代碼邏輯,在性能上,我們要知道在渲染層浪費的性能要遠大于邏輯層的代碼執行性能開銷,如果我們在小程序里采用通過props等傳遞方式,屬性是綁定在小程序標簽里面的,所以勢必要重新渲染視圖層。如果頁面結構復雜,可能會造成卡頓等情況,所以我們通過eventBus可以繞過渲染層,直接有邏輯層講數據進行推送,節約了性能的開銷。

六 事件總線二 new Vue

new Vue?這種通信方式和eventBus大致差不多,有一點不同的是,以vue實例作為eventBus中心,除了我們可以用$on,$emit之外,我們還可以用vue下的data,watch等方法,而且我們建立多個多個vue,作為不同模塊的數據通信橋梁,相比上邊那個EventBus方法,new Vue這種方法更高效,更適合vue項目場景。我們接著往下看。

1 基本使用

VueBus

import Vue from 'vue'

export default new Vue()

父組件

<template>
<div class="father" >
<input v-model="mes" /> <button @click="send" >對子組件說button>
<div>子組件對我說:{{ sonMes }}div>
<son />
div>
template>
<script>import son from './son'import VueBus from './vueBus'export default {/* 父組件 */ name:'father',components:{
son ,/* 子組件 */
},data(){return {mes:'',sonMes:'' /* 發送給子組件的信息 */
}
},created(){/* 綁定屬性 */
VueBus._data.mes = 'hello,world'
},mounted(){/* 綁定事件 */
VueBus.$on('sonSay',this.sonSay)
},methods:{/* 傳遞給子組件 */send(){
VueBus.$emit('fatherSay',this.mes)
},/* 接受子組件信息 */ sonSay(value){this.sonMes = value
},
},
}script>

我們通過?$on綁定了接受數據的方法,初始化的時候向 vue_data下面綁定了數據。

子組件

<template>
<div class="son" >
<div> 父組件對我說:{{ fatherMes }} div>
<input v-model="mes" /> <button @click="send" >對父組件說button><br/>
<button @click="getFatherMes" >獲取數據button>
div>
template>

<script>import VueBus from './vueBus' export default {name:'son',data(){return {mes:'',brotherMes:'',fatherMes:''
}
},mounted(){/* 綁定事件 */
VueBus.$on('fatherSay',this.fatherSay)
},methods:{/* 向父組件傳遞信息 */send(){
VueBus.$emit('sonSay',this.mes)
},/* 父組件對我說 */fatherSay(value){this.fatherMes = value
},/* 獲取父組件存入vue中的數據 */getFatherMes(){console.log( VueBus._data.mes )
}
},
}script>

eventBus事件總線一樣,我們還可以直接通過_data數據直接獲取到父組件傳遞的內容。

效果

a87ad4a887b1ec1ff931254d6eab8ffd.gif

2 優點

1 簡單靈活,任意組件之間通信。

和上邊eventBus通信方式一樣,這種通信方式很靈活,可以輕松在任意組件間實現通信。

2 除了通信還可以使用watch?,?computed等方法

如果我們通過vue作為通信媒介,那么只用其中的$emit$on真的是有點大材小用了,既然實例了一個vue,我們可以輕松的使用vue的?$watch?computed等功能。

3 缺點

基本上EventBus的缺點,都在vue這種通信方式中都有存在。

4 應用場景

在項目中不考慮用vuex的中小型項目中,可以考慮采用vue事件總線這種通信方式,在使用的這種方式的時候,我們一定要注意命名空間,不要重復綁定事件名稱。分清楚業務模塊,避免后續維護困難。

寫在后面

我們在寫vue項目中,具體要用什么通信方式,還要看具體的業務場景,項目大小等因素綜合評估。文章中給大家介紹了vue通信方式的優缺點,可以給大家實際工作提供一個參考。

交流討論

歡迎關注公眾號「前端試煉」,公眾號平時會分享一些實用或者有意思的東西,發現代碼之美。專注深度和最佳實踐,希望打造一個高質量的公眾號。

c72ee9887dea989c17b5170eb03d976f.png

公眾號后臺回復「小煉」加我微信,帶你飛。

如果覺得這篇文章還不錯,來個【分享、點贊、在看】三連吧,讓更多的人也看到~

430b31a30b31802e0a916a5741dd69ff.gif

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/542259.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/542259.shtml
英文地址,請注明出處:http://en.pswp.cn/news/542259.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java System類identityHashCode()方法及示例

系統類identityHashCode()方法 (System class identityHashCode() method) identityHashCode() method is available in java.lang package. identityHashCode()方法在java.lang包中可用。 identityHashCode() method is used to return the hashcode of the given object – B…

Linux中SysRq的使用(魔術鍵)

轉&#xff1a;http://www.chinaunix.net/old_jh/4/902287.html 魔術鍵&#xff1a;Linux Magic System Request Key Hacks 當Linux 系統不能正常響應用戶請求時, 可以使用SysRq小工具控制Linux. 一 SysRq的啟用與關閉 要想啟用SysRq, 需要在配置內核時設置Magic SysRq key (CO…

鏈接服務器訪問接口返回了消息沒有活動事務,因為鏈接服務器 SQLEHR 的 OLE DB 訪問接口 SQLNCLI10 無法啟動分布式事務。...

查看一下MSDTC啟動是否正確1、運行 regedt32&#xff0c;瀏覽至 HKEY_LOCAL_MACHINE\Software\Microsoft\MSDTC。添加一個 DWORD 值 TurnOffRpcSecurity&#xff0c;值數據為 1。2、重啟MS DTC服務。3、打開“管理工具”的“組件服務”。a. 瀏覽至"啟動管理工具"。b.…

micropython 蜂鳴器_基于MicroPython的TPYBoard微信遠程可燃氣體報警器的設計與實現...

前言在我們平時的生活中&#xff0c;經常看到因氣體泄漏發生爆炸事故的新聞。房屋起火、人體中毒等此類的新聞報道層出不窮。這種情況下&#xff0c;人民就發明了可燃氣體報警器。當工業環境、日常生活環境(如使用天然氣的廚房)中可燃性氣體發生泄露&#xff0c;可燃氣體報警器…

Java PropertyPermission getActions()方法與示例

PropertyPermission類的getActions()方法 (PropertyPermission Class getActions() method) getActions() method is available in java.util package. getActions()方法在java.util包中可用。 getActions() method is used to get the list of current actions in the form of…

源碼安裝nginx以及平滑升級

源碼安裝nginx以及平滑升級作者&#xff1a;尹正杰版權聲明&#xff1a;原創作品&#xff0c;謝絕轉載&#xff01;否則將追究法律責任。歡迎加入&#xff1a;高級運維工程師之路 598432640這個博客不方便上傳軟件包&#xff0c;我給大家把軟件包放到百度云鏈接&#xff1a;htt…

ajax 跨站返回值,jquery ajax 跨域問題

補充回答&#xff1a;你的動態頁只是一個請求頁。例如你新建一個 get.asp 頁面&#xff0c;用以下代碼&#xff0c;在服務端實現像URL異步(ajax)請求&#xff0c;將請求結果輸出。客戶端頁面再次用ajax(JS或者jquery的)向get.asp請求數據。兩次ajax完成異域數據請求。get.asp代…

Bootstrap學習筆記系列1-------Bootstrap網格系統

目錄 Bootstrap網格系統 學習筆記簡單網格偏移列嵌套列列排序Bootstrap網格系統 學習筆記 簡單網格 先上代碼再解釋 <!DOCTYPE html> <html><head><title>Bootstrap 模板</title><meta charset"utf-8"><!-- 引入 Bootstrap -…

Java類類的getDeclaringClass()方法和示例

類的類getDeclaringClass()方法 (Class class getDeclaringClass() method) getDeclaringClass() method is available in java.lang package. getDeclaringClass()方法在java.lang包中可用。 getDeclaringClass() method is used to return the declared Class object denotin…

樂高泰坦機器人視頻解說_“安防”機器人將亮相服貿會

可巡視園區、自動避障、自動充電&#xff0c;實現24小時巡邏&#xff0c;與后臺鏈接實時視頻監控&#xff0c;異常檢測……17日下午&#xff0c;北青-北京頭條記者在特斯聯科技集團有限公司的展廳中看到&#xff0c;一款“身懷絕技”的“安防”機器人備受關注。這款機器人也將在…

ios上傳文件云服務器上,ios文件上傳服務器

ios文件上傳服務器 內容精選換一換在當前的遷移流程中&#xff0c;可能會存在遷移后ECS控制臺鏡像名稱與實際操作系統不一致的現象。在當前機制下&#xff0c;該現象屬于正常現象。該處顯示的是下發ECS時使用的鏡像名稱&#xff0c;而不是操作系統名稱。如果設置目的端時使用的…

這是一個UIImage集合類,可以很方便的對圖片的染料(著色),增加亮度(閃電)和降低亮度(黑)和其他擴展的功能模塊。...

2019獨角獸企業重金招聘Python工程師標準>>> 這是一個UIImage集合類&#xff0c;可以很方便的對圖片的染料&#xff08;著色&#xff09;&#xff0c;增加亮度&#xff08;閃電&#xff09;和降低亮度&#xff08;黑&#xff09;和其他擴展的功能模塊。 在swift下實…

python爬取酷狗音樂top500_python獲取酷狗音樂top500的下載地址 MP3格式

下面先給大家介紹下python獲取酷狗音樂top500的下載地址 MP3格式&#xff0c;具體代碼如下所示&#xff1a;# -*- coding: utf-8 -*-# Time : 2018/4/16# File : kugou_top500.py# Software: PyCharm# pyVer : python 2.7import requests,jsonheaders{UserAgent : Mozilla/5.0 …

微商相冊一直顯示服務器偷懶,【小程序】微商個人相冊多端小程序源碼以及安裝...

程序介紹學習node.js順便接的400元單子&#xff0c;前后端都是自己寫&#xff0c;相比自己以前寫的&#xff0c;這次相對來說比較規范&#xff0c;用于個人相冊展示&#xff0c;適合微商&#xff0c;有客服聯系&#xff0c;無需后臺管理系統&#xff0c;小程序上直接進行管理&a…

stl優先隊列定義可以嗎_C ++ STL | 用戶定義的優先級隊列比較器

stl優先隊列定義>可以嗎In this article, we are going to see how to write your comparator function for priority queue in C STL using the lambda function. This is going to help you certainly to use priority queue more widely when you may have skipped think…

python編程求三角形面積公式_python編程 輸入三角形的三條邊,計算三角形的面積\...

展開全部# -*- coding: UTF-8 -*-# Filename : test.py# author by : www.runoob.coma float(input(輸入三角62616964757a686964616fe59b9ee7ad9431333433633338形第一邊長: ))b float(input(輸入三角形第二邊長: ))c float(input(輸入三角形第三邊長: ))# 計算半周長s (a …

ipfs分布式存儲網絡服務器系統,IPFS分布式存儲是什么意思 分布式云存儲服務器詳解...

一直以來&#xff0c;數據的安全性&#xff0c;存儲的隱私性都是用戶很重視的方面。基于此&#xff0c;再加上現在媒體對于分布式存儲的瘋狂報道&#xff0c;分布式存儲一詞再度涌入了大家的視野之中&#xff0c;接下來IPFS新說就為大家詳解一下有關IPFS分布式存儲的知識。VIPF…

c# 插入樹形數據#_C#數據類型能力問題 套裝1

c# 插入樹形數據#This section contains aptitude questions and answers on C# data types (set 1). 本節包含有關C&#xff03;數據類型(集合1)的能力問題和答案。 1) "int" is an alias of _________. System.Int16System.Int32System.Int64System.Byte Answer &…

python django框架怎么爬蟲步驟_[Python爬蟲]---Django視頻教程

[↓↓↓資源簡介↓↓↓]Django是一個開放源代碼的Web應用框架&#xff0c;由Python寫成。采用了MVC的框架模式&#xff0c;即模型M&#xff0c;視圖V和控制器C。它最初是被開發來用于管理勞倫斯出版集團旗下的一些以新聞內容為主的網站的&#xff0c;即是CMS(內容管理系統)軟件…

小程序 || 語句_C ++開關語句| 查找輸出程序| 套裝1

小程序 || 語句Program 1: 程序1&#xff1a; #include <iostream>using namespace std;int main(){switch (printf("Hello World")) {case 0x09:cout << " India";break;case 0x0A:cout << " Australia";break;case 0x0B:co…