Vue.js實現(xiàn)數(shù)據(jù)響應的方法
許多前端JavaScript框架(例如Angular,React和Vue)都有自己的數(shù)據(jù)相應引擎。通過了解相應性及其工作原理,您可以提高開發(fā)技能并更有效地使用JavaScript框架。在視頻和下面的文章中,我們構(gòu)建了您在Vue源代碼中看到的相同類型的Reactivity。
如果您觀看此視頻而不是閱讀文章,請觀看系列中的下一個視頻,與Vue的創(chuàng)建者Evan You討論反應性和代理。
💡 The Reactivity System
當你第一次看到它時,Vue的響應系統(tǒng)看起來很神奇。拿這個簡單的Vue應用程序:


不知何故,Vue只知道如果價格發(fā)生變化,它應該做三件事:
- 更新我們網(wǎng)頁上的價格值。
- 重新計算乘以price * quantity的表達式,并更新頁面。
- 再次調(diào)用totalPriceWithTax函數(shù)并更新頁面。
但是等等,你應該會覺得奇怪,當價格變化時,Vue如何知道要更新什么,以及它如何跟蹤所有內(nèi)容?

這不是JavaScript編程常規(guī)的工作方式。
如果你不明白,那我們試著看看常規(guī)的JavaScript是怎么運行的。例如,如果我運行此代碼:

你覺得它打印什么?由于我們沒有使用Vue,它將打印10。

在Vue,我們希望每當價格或數(shù)量更新時,總計都會得到更新。我們想要:

不幸的是,JavaScript是程序性的,而不是被動的,所以這在現(xiàn)實生活中不起作用。為了使數(shù)據(jù)變化得到相應,我們必須使用JavaScript來使事情表現(xiàn)不同。
⚠️ 問題
我們需要保存計算總數(shù)的方式,以便在價格或數(shù)量變化時重新運行。
✅ 解決方案
首先,我們需要一些方法告訴我們的應用程序,“我即將運行的代碼,存儲它,我可能需要你在另一個時間運行它?!比缓笪覀儗⒁\行代碼,如果價格或數(shù)量變量得到更新,再次運行存儲的代碼。

請注意,我們在目標變量中存儲了一個匿名函數(shù),然后調(diào)用了一個記錄函數(shù)。使用ES6箭頭語法我也可以這樣寫:

請注意,我們在目標變量中存儲了一個匿名函數(shù),然后調(diào)用了一個記錄函數(shù)。使用ES6箭頭語法我也可以這樣寫:

記錄的方法:

我們正在存儲目標(在我們的例子中是{total = price * quantity}),所以我們可以稍后運行它。

這將遍歷存儲陣列中存儲的所有匿名函數(shù)并執(zhí)行它們中的每一個。
然后在我們的代碼中,我們可以:

很簡單吧?如果您需要閱讀并嘗試再次掌握它,這里的代碼就完整了。僅供參考,如果您想知道原因,我會以特定的方式對此進行編碼。


⚠️ 問題
我們可以根據(jù)需要繼續(xù)記錄目標,但是有一個更強大的解決方案可以擴展我們的應用程序。那就是一個負責維護目標列表的類,當我們需要它們重新運行時,這些目標列表會得到通知。
✅ 解決方法: 使用Class
我們可以開始解決這個問題的一種方法是將這種行為封裝到它自己的Class中,這是一個實現(xiàn)標準編程觀察者模式的依賴類。
因此,如果我們創(chuàng)建一個JavaScript類來管理我們的依賴項(它更接近Vue處理事物的方式),它可能看起來像這樣:

讓它運行:

它仍然有效,現(xiàn)在我們的代碼感覺更可靠了。只有仍然感覺有點奇怪的是target()的設(shè)置和運行。
⚠️ 問題
我們將為每個變量設(shè)置一個Dep類,并且很好地封裝了創(chuàng)建需要監(jiān)視更新的匿名函數(shù)的行為。也許觀察者功能可能是為了處理這種行為。

(這只是上面的代碼)
我們可以改為:

✅ 解決方案:觀察者功能
在我們的Watcher功能中,我們可以做一些簡單的事情:

如您所見,watcher函數(shù)接受myFunc參數(shù),將其設(shè)置為我們的全局目標屬性,調(diào)用dep.depend()以將目標添加為訂閱者,調(diào)用目標函數(shù)并重置目標。
現(xiàn)在,當我們運行以下內(nèi)容時:


您可能想知道為什么我們將target實現(xiàn)為全局變量,而不是將其傳遞到我們需要的函數(shù)中。這有一個很好的理由,這將在我們的文章結(jié)尾處揭曉。
⚠️ 問題
我們有一個Dep類,但我們真正想要的是每個變量都有自己的Dep。在我們繼續(xù)之前,先存儲一下數(shù)據(jù)。

讓我們假設(shè)我們的每個屬性(價格和數(shù)量)都有自己的內(nèi)部Dep類。

當我們運行時:

由于訪問了data.price值,我希望price屬性的Dep類將我們的匿名函數(shù)(存儲在目標中)推送到其訂閱者數(shù)組(通過調(diào)用dep.depend())。由于訪問了data.quantity,我還希望quantity屬性Dep類將此匿名函數(shù)(存儲在目標中)推送到其訂閱者數(shù)組中。

如果我有另一個匿名函數(shù),只訪問data.price,我希望只推送到價格屬性Dep類。

我什么時候想要在價格訂閱者上調(diào)用dep.notify()?我希望在設(shè)定價格時調(diào)用它們。在文章的最后,我希望能夠進入控制臺并執(zhí)行:

我們需要一些方法來掛鉤數(shù)據(jù)屬性(如價格或數(shù)量),所以當它被訪問時我們可以將目標保存到我們的訂閱者數(shù)組中,當它被更改時,運行存儲在我們的訂閱者數(shù)組中的函數(shù)。
✅ 解決方案:Object.defineProperty()
我們需要了解Object.defineProperty()函數(shù),它是簡單的ES5 JavaScript。它允許我們?yōu)閷傩远xgetter和setter函數(shù)。在我向您展示如何在Dep類中使用它之前,先簡單展示一下改函數(shù)的用法。


如您所見,它只記錄兩行。但是,它實際上并沒有獲取或設(shè)置任何值,因為我們過度使用了該功能。我們現(xiàn)在加回來吧。 get()期望返回一個值,而set()仍然需要更新一個值,所以讓我們添加一個internalValue變量來存儲我們當前的價格值。

既然我們的get和set工作正常,您認為將打印到控制臺的是什么?

因此,當我們獲取并設(shè)置值時,我們可以獲得通知。通過一些遞歸,我們可以為數(shù)組中的所有項運行它
FYI,Object.keys(data)返回對象鍵的數(shù)組。

現(xiàn)在一切都有g(shù)etter和setter,我們在控制臺上看到了這一點。

🛠 Putting both ideas together

當像這樣的一段代碼運行并獲得價格的價值時,我們希望價格記住這個匿名函數(shù)(目標)。這樣,如果價格變化,或者設(shè)置為新值,它將觸發(fā)此函數(shù)以重新運行,因為它知道此行依賴于它。所以你可以這樣想。
Get =>記住這個匿名函數(shù),當我們的值發(fā)生變化時,我們會再次運行它。
Set =>運行保存的匿名函數(shù),我們的值剛改變。
或者就我們的Dep Class而言
Price accessed (get) => 調(diào)用dep.depend()來保存當前目標
Price set => 在價格上調(diào)用dep.notify(),重新運行所有目標
讓我們結(jié)合這兩個想法,并完成我們的最終代碼。

現(xiàn)在看看會發(fā)生什么。

正是我們所希望的!價格和數(shù)量都確實是得到了實時的響應的!只要價格或數(shù)量的價值得到更新,我們的總代碼就會重新運行。
Vue文檔中的這個插圖現(xiàn)在應該開始有意義了。

你看到那個漂亮的紫色數(shù)據(jù)圈了嗎?看起來應該很眼熟!每個組件實例都有一個從getter(紅線)收集依賴項的服務觀察器實例(藍色)。當稍后調(diào)用設(shè)置程序時,它會通知監(jiān)視程序,它將導致組件重新呈現(xiàn)。下面是我自己的一些注釋的圖片。

是的,現(xiàn)在是不是覺得更有意義了。
顯然,Vue做的可能更復雜更驚喜,但你現(xiàn)在知道了基礎(chǔ)知識。
⏪ 總結(jié):所以我們學了什么?如何創(chuàng)建一個Dep類來收集依賴項(依賴)并重新運行所有依賴項(notify)。如何創(chuàng)建一個觀察程序來管理我們正在運行的代碼,這些代碼可能需要作為依賴項添加(target)。如何使用Object.defineProperty()創(chuàng)建getter和setter。
總結(jié)
以上所述是小編給大家介紹的Vue.js實現(xiàn)數(shù)據(jù)響應的方法,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
vue router+vuex實現(xiàn)首頁登錄驗證判斷邏輯
這篇文章主要介紹了vue router+vuex實現(xiàn)首頁登錄判斷邏輯,用于判斷是否登錄首頁,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-05-05
一文快速學會阻止事件冒泡的4種方法(原生js阻止,vue中使用修飾符阻止)
冒泡就是事件開始是由最具體的元素接收,然后逐層向上級傳播到較為不具體的元素,這篇文章主要給大家介紹了關(guān)于阻止事件冒泡的4種方法,文中介紹的方法分別是原生js阻止以及vue中使用修飾符阻止的相關(guān)資料,需要的朋友可以參考下2023-12-12
VUE配置proxy代理的開發(fā)測試及生產(chǎn)環(huán)境
這篇文章主要為大家介紹了VUE配置proxy代理的開發(fā)環(huán)境、測試環(huán)境、生產(chǎn)環(huán)境詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-08-08
基于Vue和Firebase實現(xiàn)一個實時聊天應用
在本文中,我們將學習如何使用Vue.js和Firebase來構(gòu)建一個實時聊天應用,Vue.js是一種流行的JavaScript前端框架,而Firebase是Google提供的實時數(shù)據(jù)庫和后端服務,結(jié)合這兩者,我們可以快速搭建一個功能強大的實時聊天應用,需要的朋友可以參考下2023-08-08
webpack vue 項目打包生成的文件,資源文件報404問題的修復方法(總結(jié)篇)
這篇文章主要介紹了解決webpack vue 項目打包生成的文件,資源文件報404問題的修復方法,需要的朋友可以參考下2018-01-01
vue3+TypeScript+vue-router的使用方法
本文詳細講解了vue3+TypeScript+vue-router的使用方法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-01-01
vue實現(xiàn)學生錄入系統(tǒng)之添加刪除功能
本文給大家?guī)硪粋€小案例基于vue實現(xiàn)學生錄入系統(tǒng)功能,代碼簡單易懂非常不錯,具有一定的參考借鑒價值,需要的朋友參考下吧2018-07-07

