https://www.jb51.net/article/159855.htm
除了使用 Vuex 方法外,vue 提供了各種各樣的組件間通信的方案。文章整理一下父子組件、兄弟組件、祖先后代組件間是如何通信的。 💬
🌊 父子組件通信
props 和 $emit 父子組件通信
子組件有時需要與父組件進行溝通,溝通的方式就是子組件 emit 事件,父組件通過監聽這個事件來做進一步動作。而父組件與子組件通信則使用 props
假設這里有一個父組件並引入了一個子組件 my-comp:
1
|
<
my-comp
v-for
=
"msg in msgs"
:key
=
"msg.id"
:msg
=
"msg"
></
my-comp
>
|
父組件有一系列 msg 數據需要通過子組件渲染,將 msg 作為 prop 傳遞給子組件即可:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
import MyComp from
'@/components/MyComp.vue'
export
default
{
name:
'home'
,
components: {
MyComp
},
data () {
return
{
msgs: [{
id: 1, data:
'hello js'
}, {
id: 2, data:
'css world'
}, {
id: 3, data:
'animated style'
}]
}
}
}
|
我們通過點擊子組件每一項觸發一個事件,父組件監聽這個事件去動態改變子組件的 color 樣式,這就是父組件監聽子組件事件,事件處理函數可以從子組件傳遞值給父組件:
1
|
<
my-comp
v-for
=
"msg in msgs"
:key
=
"msg.id"
:msg
=
"msg"
:colored
=
"colored"
@
handle-change-color
=
"handleChangeColor"
></
my-comp
>
|
首先增加一個事件 handle-change-color 當這個事件被觸發時修改名為 color 的 data,然后將 colored 通過 props 傳入到子組件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
import MyComp from
'@/components/MyComp.vue'
export
default
{
name:
'home'
,
components: {
// 注冊組件
MyComp
},
data () {
return
{
colored:
false
,
// 狀態
msgs: [{
id: 1, data:
'hello js'
}, {
id: 2, data:
'css world'
}, {
id: 3, data:
'animated style'
}]
}
},
methods: {
handleChangeColor () {
this
.colored = !
this
.colored
// 監聽事件動態改變 colored
}
// handleChangeColor (param) { // 子組件觸發的事件可能包含參數
}
}
|
然后編輯子組件:
1
2
3
4
5
|
<
div
>
<
div
@
click
=
"handleClick"
:style
=
"{color}"
>
{{msg.id}} - {{msg.data}} ⭕
</
div
>
</
div
>
|
首先渲染數據,並監聽 click 點擊事件,當點擊觸發事件處理函數 handleClick
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
export
default
{
name:
'MyComp'
,
computed: {
color () {
// color 為樣式
return
this
.colored ?
'red'
:
'black'
// 根據父組件傳入的 props 動態修改樣式
}
},
props: [
'msg'
,
'colored'
],
methods: {
handleClick (e) {
this
.$emit(
'handle-change-color'
)
// 使用 $emit 方法觸發父組件 handle-change-color 事件
// this.$emit('handler', 'param') // 還可以給事件傳遞參數
}
}
}
|
子組件接收 colored 父組件傳遞來的 prop,返回一個計算后的屬性 color,根據 colored 返回不同樣式。handleClick 處理當子組件元素被點擊時 $emit 派發父組件的 handle-change-color 事件
效果如下:
父組件 $children 操作子組件
使用 $children 操作子組件。如上述例子中,colored 被定義在父組件中,可以將其移動到子組件中,並在父組件通過 $children 訪問到子組件:
1
2
3
4
5
|
<
template
>
<
div
@
click
=
"handleClick"
class
=
"home"
>
<
my-comp
v-for
=
"msg in msgs"
:key
=
"msg.id"
:msg
=
"msg"
></
my-comp
>
</
div
>
</
template
>
|
handleClick 事件被放置在 div 中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
import MyComp from
'@/components/MyComp.vue'
export
default
{
// ...
data () {
return
{
msgs: [{
// ...
}]
}
},
methods: {
handleClick () {
this
.$children.forEach(child => {
child.$data.colored = !child.$data.colored
// 逐一控制子組件的 $data
})
}
}
}
|
在子組件中不需要 $emit 事件,只需維護一個 data:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
export
default
{
name:
'MyComp'
,
data () {
return
{
colored:
false
// colored 狀態
}
},
computed: {
color () {
return
this
.colored ?
'red'
:
'black'
}
},
props: [
'msg'
]
}
|
子組件 $parent 訪問父組件
子組件可通過 $parent 來修改父組件的 $data,因此 colored 定義在父組件中。
1
2
3
4
5
|
<
template
>
<
div
class
=
"home"
>
<
my-comp
v-for
=
"msg in msgs"
:key
=
"msg.id"
:msg
=
"msg"
:colored
=
"colored"
></
my-comp
>
</
div
>
</
template
>
|
通過 prop 傳遞 colored 參數給子組件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
import MyComp from
'@/components/MyComp.vue'
export
default
{
name:
'home'
,
components: {
MyComp
},
data () {
return
{
colored:
false
,
// 父組件維護一個 colored 狀態
msgs: [{
// ...
}]
}
}
}
|
父組件定義 colored 狀態
1
2
3
4
5
6
7
|
<
template
>
<
div
>
<
div
@
click
=
"handleClick"
:style
=
"{color}"
>
{{msg.id}} - {{msg.data}} ⭕
</
div
>
</
div
>
</
template
>
|
子組件渲染 msg 並監聽 click 事件
1
2
3
4
5
6
7
8
9
|
export
default
{
// ...
props: [
'msg'
,
'colored'
],
methods: {
handleClick (e) {
this
.$parent.$data.colored = !
this
.$parent.$data.colored
}
}
}
|
通過 $parent 訪問父組件,並修改 $data 狀態
非父子組件通信
中央事件總線
我們可以使用使用中央事件總線來處理非父子組件間的通信
具體步驟是創建一個 Vue 實例,然后 $on 監聽事件,$emit 來派發事件
1
2
3
4
|
// src/eventBus.js
import Vue from
'vue'
export
default
new
Vue()
|
首先創建並導出一個 Vue 實例
1
2
3
4
5
6
7
8
9
10
|
import bus from
'@/eventbus'
export
default
{
// ...
methods: {
handleClick (e) {
bus.$emit(
'change-color'
)
}
}
}
|
后代元素 $emit 觸發 eventBus 的事件
1
2
3
4
5
6
7
8
9
10
|
import bus from
'@/eventbus'
export
default
{
// ...
mounted () {
bus.$on(
'change-color'
, () => {
this
.colored = !
this
.colored
})
}
}
|
祖先元素 $on 方法監聽 eventBus 的事件
provide/inject
適用於祖先和后代關系的組件間的通信,祖先元素通過 provide 提供一個值,后代元素則通過 inject 獲取到這個值。這個值默認是非響應的,如果是對象那么則是響應式的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
export
default
{
name:
'home'
,
provide () {
return
{
colored:
this
.colored
// 依賴於 data
}
},
components: {
MyComp
},
data () {
return
{
colored: {
// 必須為對象
value:
false
},
msgs: [{
// ...
|
首先通過 provide 對外提供一個 colored,這個屬性依賴於 data 中的 colored,該變量必須為一個對象,才是響應式的。
⚠️ 必須為一個對象
1
2
3
4
5
|
methods: {
handleChangeColor () {
this
.colored.value = !
this
.colored.value
}
}
|
祖先組件監聽事件或其他途徑去修改 data 改變狀態。
1
2
3
4
5
6
7
8
9
|
export
default
{
name:
'MyComp'
,
inject: [
'colored'
],
// inject colored
computed: {
color () {
return
this
.colored.value ?
'red'
:
'black'
// do more...
}
},
// ...
|
后代組件通過 inject 獲取到祖先組件提供的對象,根據對象做進一步動作。
$root 直接訪問根組件
根據官方的文檔,我們可以通過 $root 來直接訪問到 Vue 實例
比方說將數據存儲在 Vue 實例中:
1
2
3
4
5
6
7
8
9
10
11
12
|
// src/main.js
new
Vue({
data () {
return
{
// 在這里!!
colored:
false
}
},
router,
store,
render: h => h(App)
}).$mount(
'#app'
)
|
然后我們在其他各個組件中都能夠使用:
1
2
3
4
5
6
7
8
|
export
default
{
name:
'MyComp'
,
// ...
mounted () {
console.log(
this
.$root)
// 直接訪問到根組件
},
// ...
}
|
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對腳本之家的支持