抽空梳理了一下Vue經常使用的組件之間的通信方式,而後想經過使用的技術進行分類整理筆記。vue
父組件向子組件傳值。web
<template>
<div id="app">
<div class="app">
<div class="title">App.vue</div>
</div>
<!-- 將text1綁定給Component1 -->
<component1 :text="text1" />
</div>
</template>
export default {
name: 'App',
components: {
Component1,
},
data(){
return{
text1:"Text From App.vue",
}
}
}
</script>
複製代碼
<template>
<div class="component1">
<div class="title">Component1</div>
<div>
<!-- 將父組件傳遞過來的text進行展現 -->
<span class="text-bold">text:</span>
{{text}}
</div>
</div>
</template>
<script>
export default {
name: "Component1",
// 經過props來接收text
props:{
text:{
type:String
}
},
}
</script>
複製代碼
父組件經過Prop傳值給子組件是屬於單向數據流,所以當父組件修改該值的時候,子組件也會隨之更新數據;而子組件是不該該在內部改變 prop的。若是你能夠這麼作,可是Vue不推薦此作法,並會在控制檯發出警告。數組
子組件調用父組件方法。markdown
<template>
<div id="app">
<div class="app">
<div class="title">App.vue</div>
<div>
<span class="text-bold">count:</span>
{{count}}
</div>
</div>
<!-- 將事件addCount綁定給Component1 -->
<component1 @addCount="addCount" />
</div>
</template>
<script>
import Component1 from "@/components/Component1";
export default {
name: 'App',
components: {
Component1
},
data(){
return{
count:0
}
},
methods:{
addCount(){
this.count++;
}
}
}
</script>
複製代碼
<template>
<div class="component1">
<div class="title">Component1</div>
<!-- Component1的button觸發addParentCount -->
<button @click="addParentCount">
add count of App.vue
</button>
</div>
</template>
<script>
export default {
name: "Component1",
methods:{
// 調用組件綁定的addCount方法
addParentCount(){
this.$emit('addCount')
}
}
}
</script>
複製代碼
this.$emit()
的第一個參數爲事件綁定的EventName,而從第二個參數開始爲函數的參數,能夠傳多個參數值,意味着能夠經過此方法從子組件傳值給父組件。app
父組件獲取子組件的值或調用子組件的方法。ide
<template>
<div id="app">
<div class="app">
<div class="title">App.vue</div>
<!-- 顯示獲取到的子組件的text -->
<div>
<span class="text-bold">text:</span>
{{text2}}
</div>
<!-- 增長子組件的count值 -->
<button @click="ChildrenCount">
add count of Component1.vue
</button>
</div>
<!-- 進行組件註冊 -->
<component1 ref="component1" />
</div>
</template>
<script>
import Component1 from "@/components/Component1";
export default {
name: 'App',
components: {
Component1,
},
data(){
return{
text2:''
}
},
mounted() {
// 獲取子組件的text1值
this.text2 = this.$refs.component1.text1 || '';
},
methods:{
// 調用子組件的方法
ChildrenCount(){
this.$refs.component1.addCount();
}
}
}
</script>
複製代碼
<template>
<div class="component1">
<div class="title">Component1</div>
<div>
<span class="text-bold">count:</span>
{{count}}
</div>
</div>
</template>
<script>
export default {
name: "Component1",
data(){
return{
// 父組件獲取到此值
text1: 'Text From Component1.vue',
count: 0
}
},
methods:{
// 父組件調用此方法
addCount(){
this.count++;
}
}
}
</script>
複製代碼
this.$refs
是組件渲染後纔會進行填充,所以沒法在計算屬性 computed
使用,打印出來會顯示 undefined
。svg
任意組件間的事件調用。函數
共有兩種方式能夠初始化EventBus,第一種方式是新建一個 eventBus.js
,內容以下:ui
import Vue from 'vue'
export const EventBus = new Vue()
複製代碼
而後使用時均在兩個組件內引入該文件。this
import { EventBus } from "../eventBus.js";
複製代碼
而第二種方式是全局註冊EventBus。
在項目的 main.js
文件下,插入註冊代碼:
Vue.prototype.$EventBus = new Vue()
複製代碼
而後使用時便可經過 this.$EventBus
調用。
後面的案例均用第二種方法實現。
<template>
<div class="component2">
<div class="title">Component2</div>
<!-- 獲取input值更新另外一個組件的count值 -->
<div>
<input type="number" placeholder="Number..." v-model="value">
</div>
<!-- 點擊button觸發事件 -->
<button @click="changeComponent1Count">
change count of Component1
</button>
</div>
</template>
<script>
export default {
name: "Component2",
data() {
return {
value:''
}
},
methods:{
// 在EventBus總線註冊changeCount事件,並將value值傳過去
changeComponent1Count(){
this.$EventBus.$emit("changeCount",this.value)
}
}
}
</script>
複製代碼
<template>
<div class="component1">
<div class="title">Component1</div>
<div>
<span class="text-bold">count:</span>
{{count}}
</div>
</div>
</template>
<script>
export default {
name: "Component1",
data(){
return{
count: 0
}
},
// 在mounted中監聽EventBus接收changeCount事件,並觸發回調函數將value值賦給count
mounted(){
this.$EventBus.$on('changeCount',(value)=> this.count = value);
}
}
</script>
複製代碼
雖然在Vue中可使用 EventBus
來做爲溝通橋樑的概念,就像是全部組件共用相同的事件中心,能夠向該中心註冊發送事件或接收事件,使得全部組件均可以上下平行地通知其餘組件,可是若使用不慎,就會形成難以維護的「災難」。
Vue是單頁應用,若是你在某一個頁面刷新了以後,與之相關的 EventBus
會被移除,這樣就致使業務走不下去。還要就是若是業務有反覆操做的頁面, EventBus
在監聽的時候就會觸發不少次,也是一個很是大的隱患。這時候咱們就須要好好處理 EventBus
在項目中的關係。一般會用到,在vue頁面銷燬時,同時移除 EventBus
事件監聽。
移除EventBus
事件監聽的方法以下:
// 移除指定事件
this.$EventBus.$off('changeCount')
// 移除全部事件
this.$EventBus.$off()
複製代碼
經過插槽嵌套的父子組件進行事件調用和傳值。
<template>
<div id="app">
<component3>
<component4></component4>
</component3>
</div>
</template>
<script>
import Component3 from "@/components/Component3";
import Component4 from "@/components/Component4";
export default {
name: 'App',
components: {
Component3,
Component4,
}
}
</script>
複製代碼
<template>
<div class="component3">
<div class="title">Component3</div>
<!-- 獲取到子組件的text1值 -->
<div>
<span class="text-bold">text:</span>
{{text2}}
</div>
<div>
<span class="text-bold">count:</span>
{{count}}
</div>
<!-- 增長子組件的count值 -->
<button @click="addChildrenCount">
add count of Component4.vue
</button>
<!-- 插槽 -->
<slot></slot>
</div>
</template>
<script>
export default {
name: "Component3",
data() {
return {
text1: 'Text From Component3.vue',
text2:'',
count: 0
}
},
mounted() {
// 獲取子組件的text1值
this.text2 = this.$children[0].text1;
// 監聽子組件調用changeCount,並將參數value賦值給父組件的count
this.$on("changeCount",value => this.count = value);
},
methods:{
addChildrenCount(){
// 調用第一個子組件綁定的addCount方法
this.$children[0].$emit('addCount');
}
}
}
</script>
複製代碼
<template>
<div class="component4">
<div class="title">Component4</div>
<!-- 獲取到父組件的text1值 -->
<div>
<span class="text-bold">text:</span>
{{text2}}
</div>
<div>
<span class="text-bold">count:</span>
{{count}}
</div>
<div>
<input type="number" placeholder="Number..." v-model="value">
</div>
<!-- 修改父組件的count值 -->
<button @click="changeParentCount">
change count of Component3.vue
</button>
</div>
</template>
<script>
export default {
name: "Component4",
data() {
return {
text1: 'Text From Component4.vue',
text2:'',
count: 0,
value:''
}
},
mounted() {
// 獲取父組件的text1值
this.text2 = this.$parent.text1;
// 監聽父組件調用addCount,並將count++
this.$on('addCount',() => this.count++);
},
methods:{
changeParentCount(){
// 調用父組件綁定的changeCount方法,並傳入value參數
this.$parent.$emit('changeCount',this.value)
},
}
}
</script>
複製代碼
同 $refs
, $parent
和 $children
是組件渲染後纔會進行填充,所以沒法在計算屬性 computed
使用。
$children
返回的是一個數組,一個父組件可能有多個子組件,但一個子組件只能有一個父組件。
父組件向任一後代組件傳值和方法,適用於正常嵌套和插槽嵌套。
<template>
<div id="app">
<component3>
<component4>
<component5></component5>
</component4>
</component3>
</div>
</template>
<script>
import Component3 from "@/components/Component3";
import Component4 from "@/components/Component4";
import Component5 from "@/components/Component5";
export default {
name: 'App',
components: {
Component3,
Component4,
Component5,
},
}
</script>
複製代碼
<template>
<div class="component3">
<div class="title">Component3</div>
<div>
<span class="text-bold">count:</span>
{{count}}
</div>
<!-- 插槽 -->
<slot></slot>
</div>
</template>
<script>
export default {
name: "Component3",
// 向後代組件提供text和執行上下文this
provide(){
return{
text:this.text1,
component3:this
}
},
methods:{
addCount(){
this.count++;
}
}
}
</script>
複製代碼
<template>
<div class="component4">
<div class="title">Component4</div>、
<!-- 顯示父組件的text值 -->
<div>
<span class="text-bold">text:</span>
{{text}}
</div>
<slot></slot>
</div>
</template>
<script>
export default {
name: "Component4",
// 接收父組件的text值
inject:['text']
}
</script>
複製代碼
<template>
<div class="component5">
<div class="title">Component5</div>
<!-- 顯示祖組件的text值 -->
<div>
<span class="text-bold">text:</span>
{{text}}
</div>
<!-- 增長祖組件的count值 -->
<button @click="addGrandParentCount">
add count of Component3.vue
</button>
</div>
</template>
<script>
export default {
name: "Component5",
// 接收祖組件的text值和執行上下文
inject:['text','component3'],
methods:{
// 經過祖組件執行上下文調用其方法
addGrandParentCount(){
this.component3.addCount();
}
}
}
</script>
複製代碼
孫組件獲取祖組件的值或調用祖組件事件。
<template>
<div class="component6">
<div class="title">Component6</div>
<div>
<span class="text-bold">count:</span>
{{count}}
</div>
<!-- 祖組件向本身組件傳遞了text1與text2和一個addCount事件 -->
<component7 :text1="text" :text2="text" @addCount="addCount" />
</div>
</template>
<script>
import Component7 from "@/components/Component7";
export default {
name: "Component6",
components:{
Component7
},
data() {
return {
text: 'Text From Component6.vue',
count: 0
}
},
methods:{
addCount(){
this.count ++
}
}
}
</script>
複製代碼
<template>
<div class="component7">
<div class="title">Component7</div>
<div>
<span class="text-bold">text:</span>
{{text1}}
</div>
<!-- 將不被父組件prop識別的attribute綁定到孫組件,也將祖組件的事件綁定到孫組件 -->
<component8 v-bind="$attrs" v-on="$listeners" />
</div>
</template>
<script>
import Component8 from "@/components/Component8";
export default {
name: "Component7",
// 父組件prop識別了text1,所以text1不會傳遞到孫組件
props:{
text1:{
type:String
}
},
components:{
Component8
}
}
</script>
複製代碼
<template>
<div class="component8">
<div class="title">Component8</div>
<div>
<span class="text-bold">text:</span>
{{text2}}
</div>
<button @click="addGrandparentCount">
add count of Component6.vue
</button>
</div>
</template>
<script>
export default {
name: "Component8",
// 孫組件獲取到祖組件的text2
props:{
text2:{
type:String
},
},
methods:{
// 孫組件調用了祖組件的addCount事件
addGrandparentCount(){
this.$emit('addCount');
}
}
}
</script>
複製代碼
$attrs
包含了父做用域中不做爲 prop 被識別 (且獲取) 的 attribute 綁定 (class 和 style 除外)。所以當 text1
已被子組件prop獲取後,在孫組件是獲取不到 text1
的。