【Vue】高階系列(五)元件間通訊

語言: CN / TW / HK

theme: vue-pro highlight: a11y-dark


嗨!~ 大家好,我是YK菌 🐷 ,一個微系前端 ✨,愛思考,愛總結,愛記錄,愛分享 🏹,歡迎關注我呀 😘 ~ [微訊號: yk2012yk2012,微信公眾號:ykyk2012]

「這是我參與11月更文挑戰的第26天,活動詳情檢視:2021最後一次更文挑戰

今天我們主要來學習Vue中元件間通訊的方式

1. 起步

1.1 元件間通訊基本原則

1) 不要在子元件中直接修改父元件的狀態資料 2) 資料在哪, 更新資料的行為(函式)就應該定義在哪

1.2 vue 元件間通訊方式

1) props 2) 自定義事件 3) 訊息訂閱與釋出 4) 全域性事件匯流排 5) slot 6) vuex【後面再說】

2. props 父 —> 子

比較常用,用於父元件子元件中傳遞資料用

2.1 使用元件標籤時

當標籤屬性傳遞進去

html <my-component name='yk' :age='3' :set-name='setName'></my-component>

2.2 定義MyComponent 時

1) 在元件內宣告所有的props

2) 方式一: 只指定名稱

javascript props: ['name', 'age', 'setName']

3) 方式二: 指定名稱和型別

javascript props: { name: String, age: Number, setNmae: Function }

4) 方式三【完整版】: 指定名稱/型別/必要性/預設值

javascript props: { name: {type: String, required: true, default:xxx}, }

2.3 注意

  • 此方式用於父元件向子元件傳遞資料
  • 所有標籤屬性都會成為元件物件的屬性, 模板頁面可以直接引用
  • 問題:
    1. 如果需要向非子後代傳遞資料必須多層逐層傳遞
    2. 兄弟元件間也不能直接props 通訊, 必須藉助父元件才可以

3. 自定義事件 $emit 子 —> 父

3.1 繫結事件監聽

```javascript // 方式一: 通過v-on 繫結 @delete_todo="deleteTodo"

// 方式二: 通過$on() this.$refs.xxx.$on('delete_todo', function (todo) { this.deleteTodo(todo) }) ```

3.2 觸發事件

javascript // 觸發事件(只能在父元件中接收) this.$emit(eventName, data)

3.3 示例

之前都是這樣繫結事件監聽 父元件傳遞給子元件

html <TodoHeader :addTodo="addTodo" /> 變成 html <TodoHeader @addTodo="addTodo" /> 或者這樣 html <TodoHeader ref="header" /> javascript mounted(){// 非同步執行程式碼 // 繫結addTodo事件監聽 // this.$on('addTodo', this.addTodo) // 給App繫結監聽,不對的 this.$refs.header.$on('addTodo', this.addTodo) }

子元件觸發事件 javascript this.addTodo(todo); // demo2中的程式碼 變成 javascript this.$emit('addTodo', todo)

3.4 注意

1) 此方式只用於子元件向父元件傳送訊息(資料) 2) 問題: 隔代元件或兄弟元件間通訊此種方式不合適

3.5 總結

  1. 適用於:子元件 ===> 父元件

  2. 使用場景:A是父元件,B是子元件,B想給A傳資料,那麼就要在A中給B繫結自定義事件(事件的回撥在A中)。

  3. 繫結自定義事件:

    1. 第一種方式,在父元件中:<Demo @yk="test"/><Demo v-on:yk="test"/>

    2. 第二種方式,在父元件中:

js <Demo ref="demo"/> ...... mounted(){ this.$refs.xxx.$on('yk',this.test) }

  1. 若想讓自定義事件只能觸發一次,可以使用once修飾符,或$once方法。

  2. 觸發自定義事件:this.$emit('yk',資料)

  3. 解綁自定義事件this.$off('yk')

  4. 元件上也可以繫結原生DOM事件,需要使用native修飾符。

  5. 注意:通過this.$refs.xxx.$on('yk',回撥)繫結自定義事件時,回撥要麼配置在methods中,要麼用箭頭函式,否則this指向會出問題!

4. EventBus事件匯流排 .$emit .$on

定義一個event-bus.js

javascript import Vue from 'vue' const eventBus = new Vue() export default eventBus

在需要用到的元件中匯入

javascript import eventBus from './event-bus' 在事件中派發到eventBus中並攜帶資料 javascript eventBus.$emit('addItem', this.title) 在需要用到資料的元件中接收資料 javascript mounted() { eventBus.$on('addItem', this.handleAddTitle) } 使用資料

javascript methods: { handleAddTitle(title){ console.log(title) } }

解綁事件監聽 javascript beforeDestroy(){ eventBus.$off('addItem', this.handleAddTitle) }

5. 訊息訂閱與釋出(PubSubJS 庫)

5.1 訂閱訊息

javascript PubSub.subscribe('msg', function(msg, data){})

5.2 釋出訊息

javascript PubSub.publish('msg', data)

5.3 示例

訂閱訊息(繫結事件監聽) ```javascript import PubSub from 'pubsub-js'

export default { mounted () { // 訂閱訊息(deleteTodo) PubSub.subscribe('deleteTodo', (msg, index) => { this.deleteTodo(index) }) } } 釋出訊息(觸發事件)javascript // this.deleteTodo(this.index) // 釋出訊息(deleteTodo) PubSub.publish('deleteTodo', this.index) ```

5.4 注意

1) 優點: 此方式可實現任意關係元件間通訊(資料)

5.5 事件的2 個重要操作

1) 繫結事件監聽(訂閱訊息) 目標: 標籤元素<button> 事件名(型別): click/focus 回撥函式: function(event){} 2) 觸發事件(釋出訊息) DOM 事件: 使用者在瀏覽器上對應的介面上做對應的操作 自定義: 編碼手動觸發

5.6 總結

  1. 一種元件間通訊的方式,適用於任意元件間通訊

  2. 使用步驟:

  3. 安裝pubsub:npm i pubsub-js

  4. 引入: import pubsub from 'pubsub-js'

  5. 接收資料:A元件想接收資料,則在A元件中訂閱訊息,訂閱的回撥留在A元件自身。

js methods(){ demo(data){......} } ...... mounted() { this.pid = pubsub.subscribe('xxx',this.demo) //訂閱訊息 }

  1. 提供資料:pubsub.publish('xxx',資料)

  2. 最好在beforeDestroy鉤子中,用PubSub.unsubscribe(pid)取消訂閱。

```html

```

```html

```

6. 元件間通訊4: slot

6.1 理解

此方式用於父元件向子元件傳遞標籤資料

6.2 子元件: Child.vue

html <template> <div> <slot name="xxx">不確定的標籤結構1</slot> <div>元件確定的標籤結構</div> <slot name="yyy">不確定的標籤結構2</slot> </div> </template>

6.3 父元件: Parent.vue

html <child> <div slot="xxx">xxx 對應的標籤結構</div> <div slot="yyy">yyyy 對應的標籤結構</div> </child>

回顧一下插槽的知識

匿名slot

子元件內部定義一個佔位符,父元件使用時可以向元件標籤中插入任何內容替換子元件slot中的內容

具名slot

給slot元素指定一個name後,可以分發多個內容

例子 子元件模板定義

```html ``` 父元件使用

```html

標題

內容

更多

底部

最後相當於html

標題

內容

更多

這裡的`slot`已經廢棄了,用`v-slot`替代 必須由`template`標籤包裹,且`v-slot`可以簡寫成`#`html

內容

更多

```

作用域插槽

子元件的資料通過標籤傳給父元件 ```javascript

```

父元件接收資料並使用

javascript <current-user> <template v-slot:default="slotProps"> {{ slotProps.user.age }} </template> </current-user> 物件結構賦值更簡潔

javascript <current-user> <template v-slot:default="{ user }"> {{ user.age }} </template> </current-user>

最後,歡迎關注我的專欄,和YK菌做好朋友

「其他文章」