前置
大小 vue 項目都離不開組件通訊, 在這里總結(jié)一下vue組件通訊方式并列出, 都是簡單的例子. 適合像我這樣的小白。如有錯誤,歡迎指正。
溫馨提示: 下文沒有列出 vuex, vuex 也是重要的組件通訊方式。
props
* 最常用的組件通訊方式
* 值可以是數(shù)組或?qū)ο?,使用對象時可以配置高級選項,如類型檢測、自定義驗證和設(shè)置默認(rèn)值
* 方向:父 -> 子
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 用來觸發(fā)當(dāng)前實例上的事件
* 方向:父 -> 子
* 參數(shù)一:來觸發(fā)的當(dāng)前實例上的事件函數(shù)
* 參數(shù)二:附加參數(shù),傳給監(jiān)聽器回調(diào)
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 的第一個參數(shù)不在是當(dāng)前實例上的事件函數(shù)
* 方向:子 -> 父
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 實現(xiàn)雙向數(shù)據(jù)綁定
* v-model 也可以用來傳值
* 有局限性,只能傳 input value <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: 父實例,如果當(dāng)前實例有的話
* $children: 當(dāng)前實例的直接子組件
* $parent $childred 通過封裝可以實現(xiàn)不同方向的傳值
$children 并不保證順序,也不是響應(yīng)式的??梢允褂靡粋€數(shù)組配合 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 }, }
簡單封裝一下即可實現(xiàn)$parent 配合 $emit 實現(xiàn)跨級向上傳值。
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)
簡單封裝一下即可實現(xiàn)$children 配合 $emit 實現(xiàn)向下傳值。
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" 傳入內(nèi)部組件
* 只能在 <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 事件監(jiān)聽器。
* 不含 .native 修飾器修飾的時間監(jiān)聽器。
* 可以通過 v-on="$listeners" 傳入內(nèi)部組件(孫子組件)。
* 方向:父 -> 子
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 不推薦直接用于應(yīng)用程序代碼中
* 與 React
的上下文特性很相似。這對選項需要一起使用,以允許一個祖先組件向其所有子孫后代注入一個依賴,不論組件層次有多深,并在起上下游關(guān)系成立的時間里始終生效
* provide 選項應(yīng)該是一個對象或返回一個對象的函數(shù)。該對象包含可注入其子孫的屬性。在該對象中你可以使用 ES2015 Symbols 作為
key,但是只在原生支持 Symbol 和 Reflect.ownKeys 的環(huán)境下可工作
* provide 和 inject 綁定并不是可響應(yīng)的。這是 vue 刻意為之
* 如果你傳入了一個可監(jiān)聽的對象,那么其對象的屬性還是可響應(yīng)的
這里有一個簡單的示例:
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 可以讓一個對象可響應(yīng)
* vue 內(nèi)部會用它來處理 data 函數(shù)返回的對象
* 返回的對象可以直接用于渲染函數(shù)和計算屬性內(nèi),并且會在發(fā)生改變時觸發(fā)相應(yīng)的更新
* 可以作為最小化的跨組件狀態(tài)存儲器,用于簡單的場景
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 可以實現(xiàn)嵌套組件之間的數(shù)據(jù)傳遞
* 這兩個函數(shù)只能在 setup 函數(shù)中使用
* 父級組件中使用 provide 函數(shù)向下傳遞數(shù)據(jù)
* 子級組件中使用 inject 獲取上層傳遞過來的數(shù)據(jù)
* 不限層級。
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('數(shù)據(jù)名稱', 要傳遞的數(shù)據(jù)) provide("customVal",
"我是父組件向子組件傳遞的值"); } }; </script>
Son.vue
<template> <h3>{{ customVal }}</h3> </template> <script> import { inject }
from "@vue/composition-api"; export default { setup() { //調(diào)用 inject
函數(shù),通過指定的數(shù)據(jù)名稱,獲取到父級共享的數(shù)據(jù) const customVal = inject("customVal"); return {
customVal }; } }; </script>
父組件可以通過 ref 創(chuàng)建響應(yīng)式數(shù)據(jù)通過 provide 共享給子組件。
熱門工具 換一換