Vue 3.0雙向數據綁定實現原理

Vue3 的數據雙向綁定是通過響應式系統來實現的。相比于 Vue2,Vue3 在響應式系統上做了很多改進,主要使用了 Proxy 對象來替代原來的 Object.defineProperty。本文將介紹?Vue3 數據雙向綁定的主要特點和實現方式。

1. 響應式系統

1.1. Proxy對象

Vue3 使用 JavaScript 的 Proxy 對象來實現響應式數據。Proxy 可以監聽對象的所有操作,包括讀取、寫入、刪除屬性等,從而實現更加靈活和高效的響應式數據。

1.2. reactive函數

Vue3 提供了一個 reactive 函數來創建響應式對象,通過 reactive 函數包裝的對象會變成響應式數據,Vue 會自動跟蹤這些數據的變化。

import { reactive } from 'vue';const state = reactive({message: 'Hello Vue3'
});

1.3. ref函數

對于基本數據類型,如字符串、數字等,Vue3 提供了 ref 函數來創建響應式數據,使用 ref 包裝的值可以在模板中進行雙向綁定。

import { ref } from 'vue';const count = ref(0);

2. 雙向綁定

Vue3 中的雙向綁定主要通過 v-model 指令來實現,適用于表單元素,如輸入框、復選框等。以下是一個簡單的示例:

<template><input v-model="message" /><p>{{ message }}</p>
</template><script>
import { ref } from 'vue';export default {setup() {const message = ref('');return {message}}
}
</script>

在 Vue3 中,v-model?的使用更加靈活,可以支持自定義組件的雙向綁定:

<template><CustomInput v-model:value="message" />
</template><script>
import { ref } from 'vue';
import CustomInput from './CustomInput.vue';export default {components: {CustomInput},setup() {const message = ref('');return {message}}
}
</script>

在 CustomInput 組件中:

<template><input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)"/>
</template><script>
export default {props: {modelValue: String}
};
</script>

下面,我們來深入了解 Vue3 如何通過源碼實現數據的雙向綁定。

3. 源碼實現

3.1.?Proxy實現響應式

Vue3 使用 Proxy 對象來實現響應式數據。Proxy 允許我們定義基本操作的自定義行為,如讀、寫、刪除、枚舉等。

以下是 Vue3 響應式系統的核心代碼片段:

function reactive(target) {return createReactiveObject(target, mutableHandlers);
}const mutableHandlers = {get(target, key, receiver) {// 依賴收集track(target, key);const res = Reflect.get(target, key, receiver);// 深度響應式處理if (isObject(res)) {return reactive(res);}return res;},set(target, key, value, receiver) {const oldValue = target[key];const result = Reflect.set(target, key, value, receiver);// 觸發更新if (oldValue != value) {trigger(target, key);}return result;},// 其他處理函數 (deleteProperty, has, ownKeys 等)
};function createReactiveObject(target, handlers) {if (!isObject(target)) {return target;}const proxy = new Proxy(target, handlers);return proxy;
}

3.2. 依賴心集與觸發更新

在響應式系統中,依賴收集和觸發更新是兩個核心概念。Vue3 使用 track和 trigger 函數來實現這兩個功能。

const targetMap = new WeakMap();function track(target, key) {const effect = activeEffect;if (effect) {let depsMap = targetMap.get(target);if (!depsMap) {targetMap.set(target, (depsMap = new Map()));}let dep = depsMap.get(key);if (!dep) {depsMap.set(key, (dep = new Set()));}if (!dep.has(effect)) {dep.add(effect);effect.deps.push(dep);}}
}function trigger(target, key) {const depsMap = targetMap.get(target);if (!depsMap) return;const effects = new Set();const add = effectsToAdd => {if (effectsToAdd) {effectsToAdd.forEach(effect => effects.add(effect));}};add(depsMap.get(key));effects.forEach(effect => effect());
}

3.3. ref實現

對于基本數據類型,Vue3 提供了 ref 函數來創建響應式數據。ref 使用一個對象來包裝值,并通過 getter和 setter 來實現響應式。

function ref(value) {return createRef(value);
}function createRef(rawValue) {if (isRef(rawValue)) {return rawValue;}const r = {__v_isRef: true,get value() {track(r, 'value');return rawValue;},set value(newVal) {if (rawValue !== newVal) {rawValue = newVal;trigger(r, 'value');}}};return r;
}function isRef(r) {return r ? r.__v_isRef === true : false;
}

3.4. v-model實現

Vue3 中的 v-model 實現依賴于響應式系統。

3.4.1. 編譯時實現

// packages/compiler-core/src/transforms/vModel.ts
export const transformModel: NodeTransform = (node, context) => {if (node.type === NodeTypes.ELEMENT) {// 對每個元素節點執行此方法return () => {// 只處理有 v-model 指令的節點const node = context.currentNodelif (node.tagType === ElementTypes.ELEMENT) {const dir = findDir(node, 'model')if (dir && dir.exp) {// 根據節點類型調用不同的處理函數const { tag } = nodeif (tag === 'input') {processInput(node, dir, context)} else if (tag === 'textarea') {processTextArea(node, dir, context)} else if (tag === 'select') {processSelect(node, dir, context)} else if (!context.inSSR) {// 組件上的 v-modelprocessComponent(node, dir, context)}}}}}
}// 處理組件上的v-model
function processComponent(node: ElementNode,dir: DirectiveNode,context: TransformContext
) {// 獲取 v-model 的參數,支持 v-model:arg 形式const { arg, exp } = dir// 默認參數是 'modelValue'const prop = arg ? arg : createSimpleExpression('modelValue', true)// 默認事件是 'update:modelValue'const event = arg? createSimpleExpression(`update:${arg.content}`, true): createSimpleExpression('update:modelValue', true)// 添加 prop 和 event 到 props 中const props = [createObjectProperty(prop, dir.exp!),createObjectProperty(event, createCompoundExpression([`$event => ((`, exp, `) = $event)`]))]// 將 v-model 轉換為組件的 props 和事件node.props.push(createObjectProperty(createSimpleExpression(`onUpdate:modelValue`, true),createCompoundExpression([`$event => (${dir.exp!.content} = $event)`])))
}

3.4.2. 運行時實現

// packages/runtime-core/src/helpers/vModel.ts
export function vModelText(el: any, binding: any, vnode: VNode) {// 處理文本輸入框的 v-modelconst { value, modifiers } = bindingel.value = value == null ? '' : value// 添加事件監聽el._assign = getModelAssigner(vnode)const lazy = modifiers ? modifiers.lazy : falseconst event = lazy ? 'change' : 'input'el.addEventListener(event, e => {// 觸發更新el._assign(el.value)})
}export function vModelCheckbox(el: any, binding: any, vnode: VNode) {// 處理復選框的 v-modelconst { value, oldValue } = bindingel._assign = getModelAssigner(vnode)// 處理數組類型的值(多選)if (isArray(value)) {const isChecked = el._modelValue? looseIndexOf(value, el._modelValue) > -1: falseif (el.checked !== isChecked) {el.checked = isChecked}} else {// 處理布爾值if (value !== oldValue) {el.checked = looseEqual(value, el._trueValue)}}
}// 輔肋函數
function getModelAssigner(vnode: VNode): (value: any) => void {// 獲取模型賦值函數const fn = vnode.props!['onUpdate:modelValue']return isArray(fn) ? (value: any) => invokeArrayFns(fn, value) : fn
}

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

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

相關文章

TIP-2021《SRGAT: Single Image Super-Resolution With Graph Attention Network》

推薦深藍學院的《深度神經網絡加速&#xff1a;cuDNN 與 TensorRT》&#xff0c;課程面向就業&#xff0c;細致講解CUDA運算的理論支撐與實踐&#xff0c;學完可以系統化掌握CUDA基礎編程知識以及TensorRT實戰&#xff0c;并且能夠利用GPU開發高性能、高并發的軟件系統&#xf…

大語言模型與多模態模型比較

一、核心差異&#xff1a;輸入數據類型與模態融合 輸入數據類型 LLM&#xff1a;僅處理文本數據&#xff0c;例如文本分類、機器翻譯、問答等任務&#xff0c;通過大規模語料庫學習語言規律。 LMM&#xff1a;支持文本、圖像、音頻、視頻等多種模態輸入&#xff0c;例如根據圖…

Apache HttpClient 5 用法-Java調用http服務

Apache HttpClient 5 核心用法詳解 Apache HttpClient 5 是 Apache 基金會推出的新一代 HTTP 客戶端庫&#xff0c;相比 4.x 版本在性能、模塊化和易用性上有顯著提升。以下是其核心用法及最佳實踐&#xff1a; 一、添加依賴 Maven 項目&#xff1a; <dependency><…

基于 Spark 的流量統計

一、引言 在互聯網行業&#xff0c;流量統計是分析網站或應用用戶行為、評估業務表現、優化資源分配以及制定營銷策略的關鍵環節。借助 Apache Spark 強大的分布式數據處理能力&#xff0c;我們可以高效地對大規模的流量數據進行統計分析&#xff0c;獲取有價值的洞察。本文將…

Python模塊化編程進階指南:從基礎到工程化實踐

一、模塊化編程核心原理與最佳實踐 1.1 模塊化設計原則 根據企業級項目實踐&#xff0c;模塊化開發應遵循以下核心原則&#xff1a; ??單一職責原則??&#xff1a;每個模塊只承擔一個功能域的任務&#xff08;如用戶認證模塊獨立于日志模塊&#xff09;??接口隔離原則…

銳捷交換機STP環路日志信息解讀

因公司網絡組建使用銳捷全系列交換機&#xff0c;近期設備巡檢時發現部分日志提示信息&#xff0c; 接入交換機NBS3100-24GT4SFP-V2&#xff0c;設備頻繁打出STP Blocking的日志信息。 誤以為是環路導致&#xff0c;故進行實驗測試&#xff0c;來驗證環路情況下會如何報日志。…

使用Python調用DeepSeek的示例

使用Python調用DeepSeek API的示例代碼,包括API密鑰的獲取、基本請求的發送以及響應處理。請確保你已經注冊了DeepSeek賬號并獲取了API密鑰。 文章目錄 前言一、獲取API密鑰二、python示例代碼三、代碼說明四、注意事項五、擴展功能總結前言 提示:這里可以添加本文要記錄的大…

mysql的not exists走索引嗎

在MySQL中&#xff0c;?NOT EXISTS子句是否使用索引取決于子查詢中關聯字段是否建立了合適的索引。以下是關鍵點總結&#xff1a; ?索引的作用?&#xff1a; 當子查詢的關聯字段&#xff08;例如B.a_id&#xff09;存在索引&#xff08;如普通B-tree索引&#xff09;時&…

Python線性回歸:從理論到實踐的完整指南

Python線性回歸&#xff1a;從理論到實踐的完整指南 線性回歸是數據科學和機器學習中最基礎且最重要的算法之一。本文將深入探討如何使用Python實現線性回歸&#xff0c;從理論基礎到實際應用&#xff0c;幫助讀者全面理解這一重要的統計學和機器學習方法。 什么是線性回歸&a…

鴻蒙OSUniApp 實現的二維碼掃描與生成組件#三方框架 #Uniapp

UniApp 實現的二維碼掃描與生成組件 前言 最近在做一個電商小程序時&#xff0c;遇到了需要掃描和生成二維碼的需求。在移動應用開發中&#xff0c;二維碼功能已經成為標配&#xff0c;特別是在電商、社交和支付等場景下。UniApp作為一個跨平臺開發框架&#xff0c;為我們提供…

Westlake-Omni 情感端音頻生成式輸出模型

簡述 github地址在 GitHub - xinchen-ai/Westlake-OmniContribute to xinchen-ai/Westlake-Omni development by creating an account on GitHub.https://github.com/xinchen-ai/Westlake-Omni Westlake-Omni 是由西湖心辰&#xff08;xinchen-ai&#xff09;開發的一個開源…

uv python 卸載

又是查了半天 官網wiki沒有 網上一堆傻子胡說 uv提示也不對 AI還在這尼瑪胡編亂造 開始 我原來裝了這幾個環境 uv python list 現在python3.7.7不需要了&#xff0c;卸載&#xff0c;直接 uv python uninstall 3.7.7 去找你自己要卸載的版本號&#xff0c;不需要整個包名復制…

使用哈希表封裝myunordered_set和myunordered_map

文章目錄 使用哈希表封裝myunordered_set和myunordered_map實現出復用哈希表框架&#xff0c;并支持insert支持迭代器的實現constKey不能被修改unordered_map支持[ ]結語 我們今天又見面啦&#xff0c;給生活加點impetus&#xff01;&#xff01;開啟今天的編程之路&#xff01…

后端框架(2):Java的反射機制

什么是java反射機制&#xff1f; 回顧之前java程序如何使用類 1.分析&#xff0c;確定類名&#xff0c;屬性名&#xff0c;方法......創建類 2.創建類的對象 3.使用 一切都是已知的。 在程序開發中&#xff0c;在哪兒需要使用哪個類的對象&#xff0c;就在那兒創建這個類對象…

ch10 課堂參考代碼

ch10 最小生成樹 生成樹&#xff1a;對于 n 個結點 m 條邊的無向圖 G&#xff0c;由全部 n 個結點和其中 n - 1 條邊構成的無向連通子圖稱為 G 的一棵生成樹。 如果圖 G 原本就不連通&#xff0c;則不存在生成樹&#xff0c;只存在生成森林。 最小生成樹&#xff08;Minimum…

費曼技巧及提高計劃

費曼技巧及提高計劃 一、什么是費曼技巧&#xff1f; 費曼技巧&#xff08;Feynman Technique&#xff09;由諾貝爾物理學獎得主理查德費曼提出&#xff0c;是一種通過“以教代學”來徹底理解復雜概念的學習方法。其核心邏輯是&#xff1a; “如果你不能簡單解釋一件事&#x…

LongRefiner:解決長文檔檢索增強生成的新思路

大語言模型與RAG的應用越來越廣泛&#xff0c;但在處理長文檔時仍面臨不少挑戰。今天我們來聊聊一個解決這類問題的新方法——LongRefiner。 背景問題&#xff1a;長文檔處理的兩大難題 使用檢索增強型生成&#xff08;RAG&#xff09;系統處理長文檔時&#xff0c;主要有兩個…

5月16日復盤-目標檢測開端

5月16日復盤 一、圖像處理之目標檢測 1. 目標檢測認知 ? Object Detection&#xff0c;是指在給定的圖像或視頻中檢測出目標物體在圖像中的位置和大小,并進行分類或識別等相關任務。 ? 目標檢測將目標的分割和識別合二為一。 ? What、Where 2. 使用場景 目標檢測用于…

MySQL基礎面試通關秘籍(附高頻考點解析)

文章目錄 一、事務篇&#xff08;必考重點&#xff09;1.1 事務四大特性&#xff08;ACID&#xff09;1.2 事務實戰技巧 二、索引優化大法2.1 索引類型全家福2.2 EXPLAIN命令實戰 三、存儲引擎選型指南3.1 InnoDB vs MyISAM 終極對決 四、SQL優化實戰手冊4.1 慢查詢七宗罪4.2 分…

Word圖片格式調整與轉換工具

軟件介紹 本文介紹的這款工具主要用于輔助Word文檔處理。 圖片排版功能 經常和Word打交道的人或許都有這樣的困擾&#xff1a;插入的圖片大小各異&#xff0c;排列也參差不齊。若不加以調整&#xff0c;遇到要求嚴格的領導&#xff0c;可能會讓人頗為頭疼。 而這款工具能夠統…