大小 vue 項目都離不開組件通訊, 在這裡總結一下vue組件通訊方式並列出, 都是
簡單的例子. 適合像我這樣的小白。如有錯誤,歡迎指正。溫馨提示: 下文沒有列出 vuex, vuex 也是重要的組件通訊方式。
props
- 最常用的組件通訊方式
- 值可以是數組或對象,使用對象時可以配置高級選項,如類型檢測、自定義驗證和設置默認值
- 方向:父 -> 子
Son.vue
<code>copyexport
default
{props
: {text
: {type
: String,required
: true, }, },mounted
() {console
.log
(this.text) /<code>
App.vue
<code>copy<
template
><
Son
text
='我是父組件提供給子組件的值'
/>template
><
script
>import
Sonfrom
'./components/dispatch/Son'
export
default
{name
:'app'
,components
: { Son, }},script
>/<code>
$refs
- 常用的方式
- 返回註冊過 ref 特性的所有 DOM 元素和組件實例
- 可以用來操作 DOM
- 可以用來傳值
- 方向:子 -> 父
Son.vue
<code>copyexport
default
{methods
: {sonFunc
() { console.log
('我是子組件的值'
) }, },}/<code>
App.vue
<code>copy<
template
><
Son
ref
="sonref"
/>template
><
script
>import
Sonfrom
'./components/dispatch/Son'
export
default
{name
:'app'
,components
: { Son, }, mounted() {this
.$refs.sonref.sonFunc() },}script
>/<code>
控制檯打印: 我是子組件的值
$emit
- $emit 用來觸發當前實例上的事件
- 方向:父 -> 子
- 參數一:來觸發的當前實例上的事件函數
- 參數二:附加參數,傳給監聽器回調
Son.vue
<code>copyexportdefault
{ mounted() {this
.$emit('customFunc'
,'我是子組件傳給父組件的值'
) },}/<code>
App.vue
<code>copy<
template
><
Son
v-on:customFunc
="fatherFunc"
/>template
><
script
>import
Sonfrom
'./components/dispatch/Son'
export
default
{name
:'app'
,components
: { Son, },methods
: { fatherFunc(value) {console
.log(value)script
>/<code>
@update
- 需要配合 .sync 使用
- 與上面的 $emit 寫法類似
- 不同之處在於$emit 的第一個參數不在是當前實例上的事件函數
- 方向:子 -> 父
Son.vue
<code>copyexportdefault
{ mounted() {this
.$emit("update:text"
,'我是子組件傳給父組件的值'
) }}/<code>
App.vue
<code>copy<
template
><
Son
:text.sync
='text'
/>template
><
script
>import
Sonfrom
"./components/dispatch/Son"
export
default
{ data() {return
{text
:''
} }, mounted() {console
.log(this
.text);script
>/<code>
接下來看下面的寫法,上面這種寫法是對如下方式的簡寫, 或者稱之為語法糖。可以不借助 .sync。
Son.vue
<code>copyexportdefault
{ mounted () {this
.$emit('update:text'
,'我是子組件傳給父組件的值'
) }}/<code>
App.vue
<code>copy /<code>
v-model
- v-model 常用來給 input 實現雙向數據綁定
- v-model 也可以用來傳值
- 有侷限性,只能傳 input value
<code>copy
"text"> /<code>
等價於:
<code>copyvalue="text"
v-on
:input="text = $event.target.value"
>/<code>
接下來看如何通過 v-model 傳值。
Son.vue
<code>copy<
template
><
input
v-bind:value
="value"
v-on:input
="$emit('input', $event.target.text)"
/>template
><
script
>export
default
{ data() {return
{value
:'我是子組件傳給父組件的值'
, } }}script
>/<code>
App.vue
<code>copy<
template
><
Son
v-model
="text"
/>template
><
script
>import
Sonfrom
'./components/dispatch/Son'
export
default
{name
:'app'
,components
: { Son, }}script
>/<code>
$parent $childred
- $parent: 父實例,如果當前實例有的話
- $children: 當前實例的直接子組件
- $parent $childred 通過封裝可以實現不同方向的傳值
$children 並不保證順序,也不是響應式的。可以使用一個數組配合 v-for 來生成子組件,使用 Array 作為真正的來源。
App.vue
<code>copyexportdefault
{data
() {return
{ value:'我是父組件的值'
, } },/<code>
Son.vue
<code>copyexport
default
{mounted
: { console.log
(this.$parent.value) // 我是父組件的值 this.$parent.value =666
console.log
(this.$parent.value) //666
},}/<code>
簡單封裝一下即可實現$parent 配合 $emit 實現跨級向上傳值。
main.js
<code>copyVue.prototype.$dispatch =function
(event, value)
{ letparent
= this.$parentwhile
(parent
) {parent
.$emit(event, value)parent
=parent
.$parent }}/<code>
這樣使用: this.$dispatch('event',value)
簡單封裝一下即可實現$children 配合 $emit 實現向下傳值。
<code>copyVue.prototype.$broadcast =function
(event, value)
{const
broadcast = children => { children.forEach
(child => { child.$emit(event, value)if
(child.$children) { broadcast(child.$children) } }) } broadcast(this.$children)}/<code>
這樣使用: this.$broadcast('event',value)
$attrs
- 獲取父組件通過 v-bind 傳過去的所有值
- class 和 style 除外
- 可以通過 v-bind="$attrs" 傳入內部組件
- 只能在 中使用
- 方向:子 -> 父
App.vue
<code>copy<
Son
:value1
="123"
:value2
="456"
/>template
>import
Sonfrom
'./components/dispatch/Son'
export
default
{name
:'app'
,components
: { Son, },}/<code>
Son.vue
<code>copy<
template
><
div
>{{$attrs}}div
>template
><
script
>export
default
{inheritAttrs
:false
,}script
>/<code>
$listener
- 獲取父作用域中的 () v-on 事件監聽器。
- 不含 .native 修飾器修飾的時間監聽器。
- 可以通過 v-on="$listeners" 傳入內部組件(孫子組件)。
- 方向:父 -> 子
App.vue
<code>copy<
template
><
Son
@customFunc
="fatherFunc"
/>template
><
script
>import
Sonfrom
'./components/dispatch/Son'
export
default
{name
:'app'
,components
: { Son, },methods
: { fatherFunc() {console
.log('666'
) }, },}script
>/<code>
Son.vue
<code>copy<
template
><
button
@click
="$listeners.customFunc()"
>看button
>
template
>/<code>
provide inject
- provide 和 inject 不推薦直接用於應用程序代碼中
- 與 React 的上下文特性很相似。這對選項需要一起使用,以允許一個祖先組件向其所有子孫後代注入一個依賴,不論組件層次有多深,並在起上下游關係成立的時間裡始終生效
- provide 選項應該是一個對象或返回一個對象的函數。該對象包含可注入其子孫的屬性。在該對象中你可以使用 ES2015 Symbols 作為 key,但是隻在原生支持 Symbol 和 Reflect.ownKeys 的環境下可工作
- provide 和 inject 綁定並不是可響應的。這是 vue 刻意為之
- 如果你傳入了一個可監聽的對象,那麼其對象的屬性還是可響應的
這裡有一個簡單的示例:
App.vue
<code>copy<
template
><
Son
/>template
><
script
>import
Sonfrom
'./components/dispatch/Son'
export
default
{name
:'app'
,components
: { Son, }, provide() {return
{text
:'我是父組件的值'
, } },}script
>/<code>
Son.vue
<code>copyexport
default
{inject
: ['text'
],mounted
() { console.log
(this.text) // 我是父組件的值 },}/<code>
事件總線
- EventBus 又稱為事件總線
- 不是一個具體的 API,EventBus 代表一種思路
- 可以看作 vuex 的究極壓縮版
App.vue
<code>copy<
template
><
div
><
Son
/>div
>template
><
script
>import
Sonfrom
'./components/dispatch/Son'
export
default
{name
:'app'
,components
: { Son, }, mounted() {this
.$EventBus.$emit('event'
,'app.vue'
) },}script
>/<code>
Son.vue
<code>copyexportdefault
{ mounted() {this
.$EventBus.$on('event'
,
function
(v
) {console
.log(v) }) },}/<code>
Observable
- observable 可以讓一個對象可響應
- vue 內部會用它來處理 data 函數返回的對象
- 返回的對象可以直接用於渲染函數和計算屬性內,並且會在發生改變時觸發相應的更新
- 可以作為最小化的跨組件狀態存儲器,用於簡單的場景
store.js
<code>copyimport Vuefrom
'vue'
export
const
store = Vue.observable({text
:'我是store裡的'
})export
const
mutations = { setText(text) { store.text = text },}/<code>
App.vue
<code>copyimport { store, mutations }from
'../store'
export
default
{ mounted() {console
.log(store.text)//
我是store裡的 mutations.setText('我在App.vue中將你改變'
)console
.log(store.text)//
我在App.vue將你改變 },}/<code>
composition-api
- composition-api 包含 vue3 的新特性
- provide 和 inject 可以實現嵌套組件之間的數據傳遞
- 這兩個函數只能在 setup 函數中使用
- 父級組件中使用 provide 函數向下傳遞數據
- 子級組件中使用 inject 獲取上層傳遞過來的數據
- 不限層級。
App.vue
<code>copy<
template
><
provideAndInject
/>template
><
script
>import
{ provide }from
"@vue/composition-api"
import
provideAndInjectfrom
"./components/provideAndInject"
export
default
{name
:"app"
,components
: { provideAndInject }, setup() {script
>/<code>
Son.vue
<code>copy<
template
><
h3
>{{ customVal }}h3
>template
><
script
>import
{ inject }from
"@vue/composition-api"
;export
default
{ setup() {script
> /<code>
父組件可以通過 ref 創建響應式數據通過 provide 共享給子組件。
關鍵字: value components 組件