50.vue 各種組件通信方法(父子 子父 兄弟 爺孫 毫無關系的組件)


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) // 直接訪問到根組件
  },
  // ...
}

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對腳本之家的支持


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM