日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

Vue组件通信原理剖析(一)事件总线的基石 $on和$emit

發(fā)布時(shí)間:2023/12/10 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Vue组件通信原理剖析(一)事件总线的基石 $on和$emit 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

首先我們先從一個(gè)面試題入手。

面試官問(wèn): “Vue中組件通信的常用方式有哪些?”
我答:
1. props
2. 自定義事件
3. eventbus
4. vuex
5. 還有常見(jiàn)的邊界情況$parent、$children、$root、$refs、provide/inject
6. 此外還有一些非props特性$attrs、$listeners

面試官追問(wèn):“那你能分別說(shuō)說(shuō)他們的原理嗎?”
我:[一臉懵逼]😳

下面我們就來(lái)一一看看他們內(nèi)部的奧秘!
如果要看別的屬性原理請(qǐng)移步到Vue組件通信原理剖析(二)全局狀態(tài)管理Vuex和Vue組件通信原理剖析(三)provide/inject原理分析

props

解決問(wèn)題:父給子傳值

// child props: {msg: {type: String,default: ''} }// parent <child msg="這是傳給子組件的參數(shù)"></child>

自定義事件

解決問(wèn)題:子給父?jìng)髦?/p> // child this.$emit('add', '這是子組件傳給父組件的參數(shù)')// parent // parantAdd是定義在父組件中的事件,事件接受的參數(shù)$event就是子組件傳給父組件的值 <child @add="parentAdd($event)"></child>

事件總線(xiàn)eventbus

解決問(wèn)題:任意兩個(gè)組件之間的傳值

// 通常我們的做法是這樣的 // main.js Vue.prototype.$bus = new Vue()// child1 this.$bus.$on('foo', handle)// child2 this.$bus.$meit('foo')

那么組件之間的通信到底是怎么實(shí)現(xiàn)的呢?on和on和onemit具體是怎么實(shí)現(xiàn)的?我們?nèi)ピ创a中找一找答案,let’s go!

// $on 的實(shí)現(xiàn)邏輯 Vue.prototype.$on = function (event: string | Array<string>, fn: Function): Component {const vm: Component = thisif (Array.isArray(event)) {for (let i = 0, l = event.length; i < l; i++) {vm.$on(event[i], fn)}} else {(vm._events[event] || (vm._events[event] = [])).push(fn)}return vm}// $emit 的實(shí)現(xiàn)邏輯 Vue.prototype.$emit = function (event: string): Component {const vm: Component = thislet cbs = vm._events[event]if (cbs) {cbs = cbs.length > 1 ? toArray(cbs) : cbsconst args = toArray(arguments, 1)const info = `event handler for "${event}"`for (let i = 0, l = cbs.length; i < l; i++) {invokeWithErrorHandling(cbs[i], vm, args, vm, info)}}return vm}// invokeWithErrorHandling 的實(shí)現(xiàn)邏輯 export function invokeWithErrorHandling (handler: Function,context: any,args: null | any[],vm: any,info: string ) {let restry {res = args ? handler.apply(context, args) : handler.call(context)} catch (e) {handleError(e, vm, info)}return res }

上面就是我們?cè)谠创a中找到的實(shí)現(xiàn),其中有一些調(diào)試代碼我已經(jīng)刪除掉,方便大家可以抓住重點(diǎn)!
下面我們來(lái)一一分析

  • 首先我們都了解vue的數(shù)據(jù)相應(yīng)是依賴(lài)于“觀察-訂閱”模式,那on、on、onemit也不例外;
  • $on用來(lái)收集所有的事件依賴(lài),他會(huì)將傳入的參數(shù)event和fn作為key和value的形式存到vm._events這個(gè)事件集合里,就像這樣vm._events[event]=[fn];
  • 而$emit是用來(lái)觸發(fā)事件的,他會(huì)根據(jù)傳入的event在vm_events中找到對(duì)應(yīng)的事件并執(zhí)行invokeWithErrorHandling(cbs[i], vm, args, vm, info)
  • 最后我們看invokeWithErrorHandling方法可以發(fā)現(xiàn),他是通過(guò)handler.apply(context, args)和handler.call(context)的形式執(zhí)行對(duì)應(yīng)的方法
  • 是不是很簡(jiǎn)單![偷笑]

    我們既然知道怎么實(shí)現(xiàn)的,那么我們就可以自定義實(shí)現(xiàn)一個(gè)Bus, 看代碼

    // Bus: 事件派發(fā)、監(jiān)聽(tīng)和回調(diào) class Bus {constructor() {this.callbacks = {}}// 收集監(jiān)聽(tīng)的回調(diào)函數(shù)$on(name, fn) {this.callbacks[name] = this.callbacks[name] || []this.callbacks[name].push(fn)}// 執(zhí)行監(jiān)聽(tīng)的回調(diào)函數(shù)$emit(name, args) {if (this.callbacks[name]) {this.callbacks[name].forEach(cb => cb(args))}} }// 在main.js中這樣使用 Vue.prototype.$bus = new Bus()

    至此,關(guān)于總線(xiàn)的原理剖析就到這里。

    全部文章鏈接

    Vue組件通信原理剖析(一)事件總線(xiàn)的基石 on和on和onemit
    Vue組件通信原理剖析(二)全局狀態(tài)管理Vuex
    Vue組件通信原理剖析(三)provide/inject原理分析

    最后喜歡我的小伙伴也可以通過(guò)關(guān)注公眾號(hào)“劍指大前端”,或者掃描下方二維碼聯(lián)系到我,進(jìn)行經(jīng)驗(yàn)交流和分享,同時(shí)我也會(huì)定期分享一些大前端干貨,讓我們的開(kāi)發(fā)從此不迷路。

    創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)

    總結(jié)

    以上是生活随笔為你收集整理的Vue组件通信原理剖析(一)事件总线的基石 $on和$emit的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。