前置
大小 vue 項目都離不開組件通訊, 在這里總結一下vue組件通訊方式並列出, 都是簡單的例子. 適合像我這樣的小白。如有錯誤,歡迎指正。
溫馨提示: 下文沒有列出
vuex,vuex也是重要的組件通訊方式。
props
- 最常用的組件通訊方式
- 值可以是數組或對象,使用對象時可以配置高級選項,如類型檢測、自定義驗證和設置默認值
- 方向:父 -> 子
Son.vue
export default {
props: {
text: {
type: String,
required: true,
},
},
mounted() {
console.log(this.text) // 我是父組件提供給子組件的值
},
}
App.vue
<template>
<Son text='我是父組件提供給子組件的值'/>
</template>
<script>
import Son from './components/dispatch/Son'
export default {
name: 'app',
components: {
Son,
}
},
</script>
$refs
- 常用的方式
- 返回注冊過
ref特性的所有 DOM 元素和組件實例 - 可以用來操作 DOM
- 可以用來傳值
- 方向:子 -> 父
Son.vue
export default {
methods: {
sonFunc() {
console.log('我是子組件的值')
},
},
}
App.vue
<template>
<Son ref="sonref"/>
</template>
<script>
import Son from './components/dispatch/Son'
export default {
name: 'app',
components: {
Son,
},
mounted() {
this.$refs.sonref.sonFunc()
},
}
</script>
控制台打印: 我是子組件的值
$emit
$emit用來觸發當前實例上的事件- 方向:子 -> 父
- 參數一:來觸發的當前實例上的事件函數
- 參數二:附加參數,傳給監聽器回調
Son.vue
export default {
mounted() {
this.$emit('customFunc', '我是子組件傳給父組件的值')
},
}
App.vue
<template>
<Son v-on:customFunc="fatherFunc" />
</template>
<script>
import Son from './components/dispatch/Son'
export default {
name: 'app',
components: {
Son,
},
methods: {
fatherFunc(value) {
console.log(value) // 我是子組件傳給父組件的值
},
},
}
</script>
@update
- 需要配合
.sync使用 - 與上面的
$emit寫法類似 - 不同之處在於
$emit的第一個參數不在是當前實例上的事件函數 - 方向:子 -> 父
Son.vue
export default {
mounted() {
this.$emit("update:text", '我是子組件傳給父組件的值')
}
}
App.vue
<template>
<Son :text.sync='text'/>
</template>
<script>
import Son from "./components/dispatch/Son"
export default {
data() {
return {
text: ''
}
},
mounted() {
console.log(this.text); // 我是子組件傳給父組件的值
}
}
</script>
接下來看下面的寫法,上面這種寫法是對如下方式的簡寫, 或者稱之為語法糖。可以不借助 .sync。
Son.vue
export default {
mounted () {
this.$emit('update:text','我是子組件傳給父組件的值')
}
}
App.vue
<Son @update:text="v => (this.value = v)" />
import Son from "./components/dispatch/Son"
export default {
mounted() {
console.log(this.value) // 我是子組件傳給父組件的值
}
}
v-model
v-model常用來給 input 實現雙向數據綁定v-model也可以用來傳值- 有局限性,只能傳
inputvalue
<input v-model="text">
等價於:
<input
v-bind:value="text"
v-on:input="text = $event.target.value"
>
接下來看如何通過 v-model 傳值。
Son.vue
<template>
<input
v-bind:value="value"
v-on:input="$emit('input', $event.target.text)"
/>
</template>
<script>
export default {
data() {
return {
value: '我是子組件傳給父組件的值',
}
}
}
</script>
App.vue
<template>
<Son v-model="text" />
</template>
<script>
import Son from './components/dispatch/Son'
export default {
name: 'app',
components: {
Son,
}
}
</script>

$parent $childred
- $parent: 父實例,如果當前實例有的話
- $children: 當前實例的直接子組件
- $parent $childred 通過封裝可以實現不同方向的傳值
$children並不保證順序,也不是響應式的。可以使用一個數組配合v-for來生成子組件,使用Array作為真正的來源。
App.vue
export default {
data() {
return {
value: '我是父組件的值',
}
},
Son.vue
export default {
mounted: {
console.log(this.$parent.value) // 我是父組件的值
this.$parent.value = 666
console.log(this.$parent.value) // 666
},
}
簡單封裝一下即可實現$parent 配合 $emit 實現跨級向上傳值。
main.js
Vue.prototype.$dispatch = function(event, value) {
let parent = this.$parent
while (parent) {
parent.$emit(event, value)
parent = parent.$parent
}
}
這樣使用: this.$dispatch('event',value)
簡單封裝一下即可實現$children 配合 $emit 實現向下傳值。
Vue.prototype.$broadcast = function(event, value) {
const broadcast = children => {
children.forEach(child => {
child.$emit(event, value)
if (child.$children) {
broadcast(child.$children)
}
})
}
broadcast(this.$children)
}
這樣使用: this.$broadcast('event',value)
$attrs
- 獲取父組件通過
v-bind傳過去的所有值 - class 和 style 除外
- 可以通過
v-bind="$attrs"傳入內部組件 - 只能在
<template>中使用 - 方向:父 -> 子
App.vue
<template>
<Son :value1="123" :value2="456" />
</template>
import Son from './components/dispatch/Son'
export default {
name: 'app',
components: {
Son,
},
}
Son.vue
<template>
<div>{{$attrs}}</div>
</template>
<script>
export default {
inheritAttrs: false,
}
</script>

$listener
- 獲取父作用域中的 ()
v-on事件監聽器。 - 不含
.native修飾器修飾的時間監聽器。 - 可以通過
v-on="$listeners"傳入內部組件(孫子組件)。 - 方向:父 -> 子
App.vue
<template>
<Son @customFunc="fatherFunc"/>
</template>
<script>
import Son from './components/dispatch/Son'
export default {
name: 'app',
components: {
Son,
},
methods: {
fatherFunc() {
console.log('666')
},
},
}
</script>
Son.vue
<template>
<button @click="$listeners.customFunc()">看</button>
</template>
provide inject
provide和inject不推薦直接用於應用程序代碼中- 與 React 的上下文特性很相似。這對選項需要一起使用,以允許一個祖先組件向其所有子孫后代注入一個依賴,不論組件層次有多深,並在起上下游關系成立的時間里始終生效
provide選項應該是一個對象或返回一個對象的函數。該對象包含可注入其子孫的屬性。在該對象中你可以使用 ES2015 Symbols 作為 key,但是只在原生支持 Symbol 和 Reflect.ownKeys 的環境下可工作provide和inject綁定並不是可響應的。這是 vue 刻意為之- 如果你傳入了一個可監聽的對象,那么其對象的屬性還是可響應的
這里有一個簡單的示例:
App.vue
<template>
<Son />
</template>
<script>
import Son from './components/dispatch/Son'
export default {
name: 'app',
components: {
Son,
},
provide() {
return {
text: '我是父組件的值',
}
},
}
</script>
Son.vue
export default {
inject: ['text'],
mounted() {
console.log(this.text) // 我是父組件的值
},
}
事件總線
- EventBus 又稱為事件總線
- 不是一個具體的 API,EventBus 代表一種思路
- 可以看作 vuex 的究極壓縮版
App.vue
<template>
<div>
<Son />
</div>
</template>
<script>
import Son from './components/dispatch/Son'
export default {
name: 'app',
components: {
Son,
},
mounted() {
this.$EventBus.$emit('event', 'app.vue')
},
}
</script>
Son.vue
export default {
mounted() {
this.$EventBus.$on('event', function(v) {
console.log(v)
})
},
}
Observable
observable可以讓一個對象可響應- vue 內部會用它來處理 data 函數返回的對象
- 返回的對象可以直接用於渲染函數和計算屬性內,並且會在發生改變時觸發相應的更新
- 可以作為最小化的跨組件狀態存儲器,用於簡單的場景
store.js
import Vue from 'vue'
export const store = Vue.observable({ text: '我是store里的' })
export const mutations = {
setText(text) {
store.text = text
},
}
App.vue
import { store, mutations } from '../store'
export default {
mounted() {
console.log(store.text) //我是store里的
mutations.setText('我在App.vue中將你改變')
console.log(store.text) //我在App.vue將你改變
},
}
composition-api
composition-api包含 vue3 的新特性provide和inject可以實現嵌套組件之間的數據傳遞- 這兩個函數只能在
setup函數中使用 - 父級組件中使用
provide函數向下傳遞數據 - 子級組件中使用
inject獲取上層傳遞過來的數據 - 不限層級。
App.vue
<template>
<provideAndInject />
</template>
<script>
import { provide } from "@vue/composition-api"
import provideAndInject from "./components/provideAndInject"
export default {
name: "app",
components: {
provideAndInject
},
setup() {
// provide('數據名稱', 要傳遞的數據)
provide("customVal", "我是父組件向子組件傳遞的值");
}
};
</script>
Son.vue
<template>
<h3>{{ customVal }}</h3>
</template>
<script>
import { inject } from "@vue/composition-api";
export default {
setup() {
//調用 inject 函數,通過指定的數據名稱,獲取到父級共享的數據
const customVal = inject("customVal");
return {
customVal
};
}
};
</script>
父組件可以通過 ref 創建響應式數據通過 provide 共享給子組件。
