02 Vue中組件通信(上)

組件是Vue.js強(qiáng)大的功能之一,而組件實(shí)例的作用域是相互獨(dú)立的,那么在開發(fā)的過程中踢俄,組件與組件之間肯定是相互聯(lián)系的睦疫,那么,組件之間是如何通信的,是如何傳遞數(shù)據(jù)的呢?

一: 幾種常見的組件

父子組件、兄弟組件俩檬、跨級組件;而相應(yīng)的通信也分為:父子組件通信碾盟、兄弟組件通信棚辽、跨級組件通信。
那么冰肴,針對不同的組件屈藐,我們?nèi)绾芜M(jìn)行通信呢?接下來我們來看一下都有哪些組件間的通信方式熙尉。

二: 組件間的通信方式

1. 父子組件通信(props/$emit)
a. 父傳子 --- 父組件通過props向下傳遞數(shù)據(jù)給子組件

父組件通過props的方式來給子組件傳值联逻,例子:子組件son.app如何獲取父組件App.vue中的數(shù)據(jù)titlelists,動態(tài)傳值要結(jié)合使用v-bind

// App.vue 父組件
<template>
  <div id="app">
// 1. 給 prop 傳遞一個靜態(tài)的值检痰,title 為 prop 的名稱(名稱為自定義名稱)包归,等號后面的為 prop 要傳遞的值
// 2. prop 通過 v-bind 動態(tài)賦值 , 前者 lists 為自定義名稱便于子組件調(diào)用,后者 list 為要傳遞數(shù)據(jù)名即 data中的 lists
    <son  title = "這是父組件傳來的靜態(tài)值"  :lists="lists"></son> 
  </div>
</template>

<script>
import son from './components/son'
export default {
  name: 'app',
  components:{son},
  data(){
    return {
      lists: ['寶玉','黛玉','寶釵']
    }
  }
  
}
</script>
// son.vue 子組件
<template>
  <div class="son">
    <div>{{title}}</div> // 渲染從父組件中接收到的數(shù)據(jù)
    <ul>
      <li v-for="list in lists" >{{list}}</li> // 遍歷傳遞過來的值铅歼,后渲染到頁面
    </ul>
  </div>
</template>
<script>
export default {
  props: ['title','lists']    // 數(shù)組中的內(nèi)容就是父組件中子標(biāo)簽自定義名字
}
</script>
b. 子傳父
  • 通過自定義事件模式 $on$emit

子組件使用$emit來觸發(fā)事件公壤,父組件使用$on來監(jiān)聽事件换可,一旦子組件觸發(fā)該事件,則父組件就會接收該事件并作出相應(yīng)處理境钟。類似與JavaScript中的發(fā)布訂閱模式锦担。

  • vm.$on(evet,callback)
    • 參數(shù)
      • {string | Array<string>} event(數(shù)組只在 2.2.0+ 中支持)
      • {Function} callback
    • 用法
      監(jiān)聽當(dāng)前實(shí)例上的自定義事件。事件可以由vm.$emit觸發(fā)慨削。回調(diào)函數(shù)會接收所有傳入事件觸發(fā)函數(shù)的額外參數(shù)套媚。
    • 示例:
      vm.$on('test', function (msg) {
            console.log(msg)
      })
      vm.$emit('test', 'hi')
      // => "hi"
      
  • vm.$emit(evnetname,[...args])
    • 參數(shù):
      • {string} eventName
      • [...args]
        觸發(fā)當(dāng)前實(shí)例上的事件缚态。附加參數(shù)都會傳給監(jiān)聽器回調(diào)。

下述代碼為堤瘤,子組件son.vue向父組件App.vue傳遞一個數(shù)據(jù)

// son.vue 子組件
<template>
  <div class="son">
    <button @click = "$emit('msghandle',msg)">點(diǎn)擊</button>  // msghandle 為自定義事件的名字玫芦,msg 為要傳遞的數(shù)據(jù)
  </div>
</template>
<script>
export default {
  props: ['title','lists','acount'],
  data(){
    return {
      msg: "這是從子組件傳遞過來的信息"
    }
  }
}
// App.vue 父組件
<template>
  <div id="app">
    <son @msghandle="handle"></son> // msghandle 事件名稱與子組件保持一致,handle 為回調(diào)函數(shù)本辐,接收傳遞過來的額外參數(shù)
    <div>{{msg}}</div>
  </div>
</template>

<script>
import son from './components/son'
export default {
  name: 'app',
  components:{son},
  data(){
    return {
      msg:''
    }
  },
  methods: {
    handle(e){    // 執(zhí)行子組件觸發(fā)的事件 桥帆, e為子組件傳遞過來的參數(shù)
      this.msg = e  
}
  } 
}
</script>

上述代碼實(shí)現(xiàn)的功能,當(dāng)點(diǎn)擊 [點(diǎn)擊] 按鈕時慎皱,父組件中會接收并顯示來自組件的信息老虫。
點(diǎn)擊前

當(dāng)點(diǎn)擊按鈕時
點(diǎn)擊后
  • 子傳父(在組件中使用v--model)

$emit的代碼,這行代碼實(shí)際上會觸發(fā)一個 input事件, input后的參數(shù)就是傳遞給v--model綁定 的屬性的值, v--model 其實(shí)是一個語法糖,這背后其實(shí)做了兩個操作

  • v--bind 綁定一個 value 屬性, v--on 指令給當(dāng)前元素綁定input 事件
  • 要使用v--model,要做到:接收一個 value 屬性茫多。 在有新的 value時觸發(fā)input 事件
    舉個例子:
// App.vue 
<template>
  <div id="app">
    <son v-model="message"></son>
    <p>{{message}}</p>
  </div>
</template>

<script>
import son from './components/son'
export default {
  name: 'app',
  components:{son},
  data(){
    return {
      message:'hello'
    }
  }
}
</script>
// son.vue 
<template>
  <div class="son">
    <div>
      <input type="text" v-model="mymessage" @change="change"> 
    </div>
  </div>
</template>
<script>
export default {
  props: ['value'],  //v-model 會自動傳遞一個字段為 value 的 props 屬性
  data(){
    return {
      mymessage: this.value  
    }
  },
methods: {
    change() {
      this.$emit('input', this.mymessage); //通過如此調(diào)用可以改變父組件上 v-model 綁定的值
    }
}
</script>

在上面的實(shí)例代碼中祈匙,我們定義了App.vueson.vue 兩個組件,這兩個組件是父子關(guān)系天揖,v-model 也只能實(shí)現(xiàn)父子組件之間的通信夺欲。

  • App.vue 組件中,我們給自定義的 son 組件實(shí)現(xiàn)了 v-model綁定了 message 屬性今膊。此時相當(dāng)于給 son 組件傳遞了 value 屬性和綁定了input 事件些阅。
  • 順理成章,在定義的 son 組件中斑唬,可以通過 props獲取value屬性市埋,根據(jù) props 單向數(shù)據(jù)流的原則,又將value 緩存在了 data里面的mymessage上赖钞,再在input 上通過v-model 綁定了 mymessage 屬性和一個 change 事件腰素。當(dāng)input 值變化時,就會觸發(fā) change事件雪营,處理 App.vue組件通過v-modelson組件綁定的 input事件弓千,觸發(fā) App組件中 message 屬性值的變化,完成 son子組件改變 App組件的屬性值献起。
2. 兄弟組件通信

這種方法通過一個空的Vue實(shí)例作為中央事件總線(事件中心)洋访,用它來觸發(fā)事件和監(jiān)聽事件,巧妙而輕量地實(shí)現(xiàn)了任何組件間的通信镣陕,包括父子、兄弟姻政、跨級呆抑。當(dāng)我們的項(xiàng)目比較大時,可以選擇更好的狀態(tài)管理解決方案vuex

  1. 大致步驟:
const bus = new Vue()
Vue.prototype.$bus = bus
$bus.$emit(事件名,數(shù)據(jù));
$bus.$on(事件名,data => {});
  1. 舉個例子
    假設(shè)兄弟組件有三個汁展,分別是A鹊碍、B、C組件食绿,C組件如何獲取A或者B組件的數(shù)據(jù)
// 定義中央事件總線侈咕,并將中央事件總線掛在 Vue.prototype 上,這樣所有組件都能訪問到了
// main.js 文件
import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

const bus = new Vue()
Vue.prototype.$bus = bus;

new Vue({
  render: h => h(App),
}).$mount('#app')
// A.vue 組件A
<template>
  <div>
    <h3>A組件: {{name}}</h3>
    <button @click = "send">將數(shù)據(jù)發(fā)給C組件</button>
  </div>
</template>
<script>
export default {
  data(){
    return {
      name: "Nick"
    }
  },
  methods:{
    send(){
      this.$bus.$emit('data-a',this.name)
    }
  }
}
</script>
// B.vue 組件B
<template>
  <div>
    <h3>B組件:{{age}}</h3>
    <button @click="send">將數(shù)據(jù)發(fā)給C組件</button>
  </div>
</template>
<script>
export default {
  data(){
    return {
      age: 30
    }
  },
  methods:{
    send(){
      this.$bus.$emit('data-b',this.age)
    }
  }
}
</script>
<template>
  <div>
    <h3>C組件:{{name}} {{age}}</h3>
  </div>
</template>
<script>
export default {
  data(){
    return {
      name:'',
      age:''
    }
  },
  // mounted 在模板編譯后執(zhí)行
  mounted(){
    this.$bus.$on('data-a',name => {
      this.name = name
    })
    this.$bus.$on('data-b',age => {
      this.age = age
    })
  }
}
</script>
// App.vue 文件中
<template>
  <div id="app">
    <A></A>
    <B></B>
    <C></C>
  </div>
</template>

<script>
import A from './components/A'
import B from './components/B'
import C from './components/C'

export default {
  name: 'app',
  // components:{son},
  components:{A,B,C},
</script>

在上面的實(shí)例中器紧,我們定義了組件 A 和組件 B和組件C耀销,但三個組件之間沒有任何的關(guān)系。
1)铲汪、 首先我們通過 new Vue()實(shí)例化了一個 Vue 的實(shí)例熊尉,也就是我們這里稱呼的中央事件總線 bus,然后將其掛載Vue.prototype.$bus掌腰,使得所有的業(yè)務(wù)邏輯組件都能夠訪問到狰住;
2)、 然后定義了組件 A辅斟,在組件 A 里面定義了一個處理的方法 send转晰,主要定義觸發(fā)一個 data-a 事件,并傳遞一個參數(shù)士飒;然后定義了組件 B查邢,在組件 B 里面定義了一個處理的方法 send,主要定義觸發(fā)一個 data-b 事件酵幕,并傳遞一個參數(shù)扰藕;
3). 最后定義了組件 C,在組件 C 里面的 mounted 生命周期監(jiān)聽了組件 A 和組件B里面定義的 data-adata-b事件芳撒,并在回調(diào)函數(shù)里面執(zhí)行了一些邏輯處理邓深。

中央事件總線 bus 非常簡單,就是任意組件和組件之間打交道笔刹,沒有多余的業(yè)務(wù)邏輯芥备,只需要在狀態(tài)變化組件觸發(fā)一個事件,然后在處理邏輯組件監(jiān)聽該事件就可以舌菜。該方法非常適合小型的項(xiàng)目萌壳!

參考資料
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子袱瓮,更是在濱河造成了極大的恐慌缤骨,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件尺借,死亡現(xiàn)場離奇詭異绊起,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)燎斩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進(jìn)店門虱歪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人瘫里,你說我怎么就攤上這事实蔽。” “怎么了谨读?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長坛吁。 經(jīng)常有香客問我劳殖,道長,這世上最難降的妖魔是什么拨脉? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任哆姻,我火速辦了婚禮,結(jié)果婚禮上玫膀,老公的妹妹穿的比我還像新娘矛缨。我一直安慰自己,他們只是感情好帖旨,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布箕昭。 她就那樣靜靜地躺著,像睡著了一般解阅。 火紅的嫁衣襯著肌膚如雪落竹。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天货抄,我揣著相機(jī)與錄音述召,去河邊找鬼。 笑死蟹地,一個胖子當(dāng)著我的面吹牛积暖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播怪与,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼夺刑,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起性誉,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤窿吩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后错览,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體纫雁,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年倾哺,在試婚紗的時候發(fā)現(xiàn)自己被綠了轧邪。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡羞海,死狀恐怖忌愚,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情却邓,我是刑警寧澤硕糊,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站腊徙,受9級特大地震影響简十,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜撬腾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一螟蝙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧民傻,春花似錦胰默、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至彭雾,卻和暖如春碟刺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背薯酝。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工半沽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人吴菠。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓者填,卻偏偏與公主長得像,于是被迫代替她去往敵國和親做葵。 傳聞我的和親對象是個殘疾皇子占哟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 主要還是自己看的,所有內(nèi)容來自官方文檔。 介紹 Vue.js 是什么 Vue (讀音 /vju?/榨乎,類似于 vie...
    Leonzai閱讀 3,350評論 0 25
  • 什么是組件怎燥? 組件 (Component) 是 Vue.js 最強(qiáng)大的功能之一。組件可以擴(kuò)展 HTML 元素蜜暑,封裝...
    youins閱讀 9,480評論 0 13
  • 背景 ??Vue是單頁面應(yīng)用铐姚,單頁面應(yīng)用又是由組件構(gòu)成,各個組件之間又互相關(guān)聯(lián)肛捍,那么如何實(shí)現(xiàn)組件之間通信就顯得尤為...
    A鄭家慶閱讀 893評論 0 1
  • VUE介紹 Vue的特點(diǎn)構(gòu)建用戶界面隐绵,只關(guān)注View層簡單易學(xué),簡潔拙毫、輕量依许、快速漸進(jìn)式框架 框架VS庫庫,是一封裝...
    多多醬_DuoDuo_閱讀 2,710評論 1 17
  • 之前說過缀蹄,可以使用 props 將數(shù)據(jù)從父組件傳遞給子組件峭跳。其實(shí)還有其它種的通信方式,下面我們一一娓娓道來缺前。 1 ...
    deniro閱讀 3,294評論 2 27