Vue組件通信原理剖析(一)事件總線的基石 $on和$emit

首先我們先從一個面試題入手。

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

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

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

props

解決問題:父給子傳值

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

自定義事件

解決問題:子給父傳值

// child
this.$emit('add', '這是子組件傳給父組件的參數')// parent
// parantAdd是定義在父組件中的事件,事件接受的參數$event就是子組件傳給父組件的值
<child @add="parentAdd($event)"></child>

事件總線eventbus

解決問題:任意兩個組件之間的傳值

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

那么組件之間的通信到底是怎么實現的呢?on和on和onemit具體是怎么實現的?我們去源碼中找一找答案,let’s go!

// $on 的實現邏輯
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 的實現邏輯
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 的實現邏輯
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
}

上面就是我們在源碼中找到的實現,其中有一些調試代碼我已經刪除掉,方便大家可以抓住重點!
下面我們來一一分析

  1. 首先我們都了解vue的數據相應是依賴于“觀察-訂閱”模式,那on、on、onemit也不例外;
  2. $on用來收集所有的事件依賴,他會將傳入的參數eventfn作為key和value的形式存到vm._events這個事件集合里,就像這樣vm._events[event]=[fn];
  3. 而$emit是用來觸發事件的,他會根據傳入的eventvm_events中找到對應的事件并執行invokeWithErrorHandling(cbs[i], vm, args, vm, info)
  4. 最后我們看invokeWithErrorHandling方法可以發現,他是通過handler.apply(context, args)handler.call(context)的形式執行對應的方法

是不是很簡單![偷笑]

我們既然知道怎么實現的,那么我們就可以自定義實現一個Bus, 看代碼

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

至此,關于總線的原理剖析就到這里。

全部文章鏈接

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

最后喜歡我的小伙伴也可以通過關注公眾號“劍指大前端”,或者掃描下方二維碼聯系到我,進行經驗交流和分享,同時我也會定期分享一些大前端干貨,讓我們的開發從此不迷路。
在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/248809.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/248809.shtml
英文地址,請注明出處:http://en.pswp.cn/news/248809.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

display:flex彈性布局

一、背景 前段時間幫公司運維小姑娘調整她自己寫的頁面樣式時發現她用了display: flex&#xff0c;我這個后端老古董還不太懂flex&#xff0c;自愧不如啊&#xff0c;所以寫篇博客記錄學習下。 現在寫的前端頁面還停留在依賴 display 屬性 position屬性 float屬性的布局方式&…

一些好的思維方式

定理s 一、墨菲定律 觀點&#xff1a;1.任何事都沒有表面看起來那么簡單&#xff1b;2.所有的事都會比你預計的時間長&#xff1b;3.會出錯的事總會出錯&#xff1b;4.如果你擔心某種情況發生&#xff0c;那么它就更有可能發生。 墨菲定律的核心觀點就4點&#xff0c;不算復雜&…

Vue組件通信原理剖析(二)全局狀態管理Vuex

首先我們先從一個面試題入手。 面試官問&#xff1a; “Vue中組件通信的常用方式有哪些&#xff1f;” 我答&#xff1a; 1. props 2. 自定義事件 3. eventbus 4. vuex 5. 還有常見的邊界情況$parent、$children、$root、$refs、provide/inject 6. 此外還有一些非props特性$att…

初識單點登錄及JWT實現

單點登錄 多系統&#xff0c;單一位置登錄&#xff0c;實現多系統同時登錄的一種技術 &#xff08;三方登錄&#xff1a;某系統使用其他系統的用戶&#xff0c;實現本系統登錄的方式。如微信登錄、支付寶登錄&#xff09; 單點登錄一般是用于互相授信的系統&#xff0c;實現單一…

Vue組件通信原理剖析(三)provide/inject原理分析

首先我們先從一個面試題入手。 面試官問&#xff1a; “Vue中組件通信的常用方式有哪些&#xff1f;” 我答&#xff1a; 1. props 2. 自定義事件 3. eventbus 4. vuex 5. 還有常見的邊界情況$parent、$children、$root、$refs、provide/inject 6. 此外還有一些非props特性$att…

iMX6開發板-uboot-網絡設置和測試

本文章基于迅為IMX6開發板 將iMX6開發板通過網線連接到路由器&#xff0c;同時連接好調試串口&#xff0c;上電立即按 enter&#xff0c;即可進入 uboot。然后輸入命令 pri&#xff0c;查看開發板當前的配置&#xff0c;如下圖所示可以看到 ip 地址、子網掩碼 等信息。 本文檔測…

Django ajax 檢測用戶名是否已被注冊

添加一個 register.html 頁面 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body> <form><p>用戶名<input id"username" type&…

pyqt5控件

背景色設置 self.tab.setStyleSheet("background: rgb(238, 233, 233)") self.but_0.setStyleSheet("background: rgb(0, 255, 255)")樣式&#xff1a; self.but_0.setStyle(QStyleFactory.create("Windows"))字體&#xff1a; self.lineEdit.se…

詳解JDBC連接數據庫

一、概念 1. 為了能讓程序操作數據庫&#xff0c;對數據庫中的表進行操作&#xff0c;每一種數據庫都會提供一套連接和操作該數據庫的驅動&#xff0c;而且每種數據庫的驅動都各不相同&#xff0c;例如mysql數據庫使用mysql驅動&#xff0c;oracle數據庫使用oracle驅動&#xf…

ASP.NET MVC 自定義模型綁定1 - 自動把以英文逗號分隔的 ID 字符串綁定成 Listint...

直接貼代碼了&#xff1a; CommaSeparatedModelBinder.cs using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Web.Mvc;namespace MvcSample.Extensions {public class CommaSeparatedMode…

ZOJ4024 Peak

題意 給出一個數組 判斷這個數組是否形成了一個“山峰” 即中間有個數最大 從第一個數到這個數遞增 從這個數到最后一個數遞減 模擬 從兩端分別以遞增和遞減判斷 看第一個不滿足遞增或遞減的數是否相等并且沒越界就可以了 AC代碼&#xff1a; 1 #include<bits/stdc.h>2 u…

基本數據類型與String之間的轉換

字符串轉基本數據類型 調用基本數據類型對應的包裝類中的方法parseXXX(String)或valueOf(String)即可返回相應基本類型。 基本數據類型轉字符串 一種方法是將基本數據類型與空字符串&#xff08;""&#xff09;連接&#xff08;&#xff09;即可獲得其所對應的字符串…

springmvc跨域問題

1、跨域問題&#xff1a; 按照網上所有的方法試了一遍&#xff0c;都沒跨過去&#xff0c;正在無助之際&#xff0c;使用filter按照下面的方法解決的時候出現了轉機&#xff1a; 添加filter&#xff1a; package com.thc.bpm.filter;import javax.servlet.*; import javax.serv…

柳傳志給年輕人的建議:比起過日子,更要奔日子

改革開放的 40 年&#xff0c;是柳傳志實現人生價值的 40 年。 十一屆三中全會后&#xff0c;伴隨“科學的春天”&#xff0c;迎著改革開放的大潮&#xff0c;柳傳志“下海”了。但他并沒想到&#xff0c;自己選擇的電腦行業&#xff0c;讓他和聯想集團站在了潮頭。 從 1984 年…

成功秀了一波scala spark ML邏輯斯蒂回歸

1、直接上官方代碼&#xff0c;調整過的&#xff0c;方可使用 package com.test import org.apache.spark.{SparkConf, SparkContext} import org.apache.spark.mllib.classification.{LogisticRegressionModel, LogisticRegressionWithLBFGS} import org.apache.spark.mllib.e…

記錄一次查詢log的經歷

一大早發現生產數據庫的基礎資料被刪除。 由于每天都做了差異備份&#xff0c;而且是基礎資料&#xff0c;這樣數據就不會擔心找不回來。 首先通過每天的差異本分文件進行查看數據丟失的大概時間&#xff0c;查到數據丟失是在17晚上備份過后18丟失的。 然后找18號的數據庫執行記…

移動端輪播圖

1. 頁面布局 1.1 頁面框架 <body><div class"box"><div class"tupian"><img src"4.webp" alt""><img src"1.webp" alt""><img src"2.webp" alt""><…

Boost 序列化

原文鏈接&#xff1a; https://blog.csdn.net/qq2399431200/article/details/45621921 1. 編譯器 gcc, boost 1.55 2.1第一個簡單的例子 —— Hello World &#xff0c;將字符串內容歸檔到文本文件中 #include <iostream>#include <fstream>#include <string>…

docker CE 的安裝

一、Docker CE的安裝1.先決條件運行環境&#xff1a;Ubuntu 64位或者其他支持Docker的64位系統運行配置&#xff0c;linux內核版本必須大于 3.10&#xff0c;否則會因為缺少容器運行所需的功能而出錯。 2.在ubuntu下安裝Docker CEUbuntu版本? Cosmic 18.10 ? Bionic 18.04 (…

nodeJS中的異步編程

nodejs 不是單線程 在博客項目中關于異步問題&#xff1a; 1.當用戶添加一條博客時 需要通過post方式向服務器發送數據 后臺獲取用戶以post方式拿到傳送過來的數據 然后存入數據庫&#xff1a; 上面的代碼&#xff1a;創建一個空字符串 當用戶向服務器發送請求時出發data事件將…