02 Vue中組件通信(上)

組件是Vue.js強(qiáng)大的功能之一,而組件實例的作用域是相互獨立的,那么在開發(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)前實例上的自定義事件。事件可以由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ù)都會傳給監(jiān)聽器回調(diào)。

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

// son.vue 子組件
<template>
  <div class="son">
    <button @click = "$emit('msghandle',msg)">點擊</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>

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

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

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

  • 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>

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

  • App.vue 組件中,我們給自定義的 son 組件實現(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實例作為中央事件總線(事件中心),用它來觸發(fā)事件和監(jiān)聽事件,巧妙而輕量地實現(xiàn)了任何組件間的通信,包括父子、兄弟、跨級。當(dā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>

在上面的實例中,我們定義了組件 A 和組件 B和組件C,但三個組件之間沒有任何的關(guān)系。
1)、 首先我們通過 new Vue()實例化了一個 Vue 的實例,也就是我們這里稱呼的中央事件總線 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)聽該事件就可以。該方法非常適合小型的項目!

參考資料
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容