日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > vue >内容正文

vue

手把手教你剖析vue响应式原理,监听数据不再迷茫

發(fā)布時間:2023/12/4 vue 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 手把手教你剖析vue响应式原理,监听数据不再迷茫 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Object.defineProperty實現(xiàn)vue響應(yīng)式原理

  • 一、組件化基礎(chǔ)
    • 1、“很久以前”的組件化
      • (1)asp jsp php 時代
      • (2)nodejs
    • 2、數(shù)據(jù)驅(qū)動視圖(MVVM,setState)
      • (1)數(shù)據(jù)驅(qū)動視圖 - Vue MVVM
      • (2)數(shù)據(jù)驅(qū)動視圖 - React setState
      • (3)總結(jié)
  • 二、Vue響應(yīng)式
    • 1、vue的響應(yīng)式是什么
    • 2、Object.defineProperty基本用法
    • 3、Oject.defineProperty實現(xiàn)響應(yīng)式
      • (1)監(jiān)聽對象
      • (2)監(jiān)聽數(shù)組
      • (3)幾個缺點
  • 四、結(jié)束語

近期在對 vue 的學(xué)習(xí)到一定階段之后,在想著自己能不能造些東西。于是身邊的小伙伴建議說可以從看 vue 的源碼開始,毫無頭緒的我原本遲遲不敢邁出這一步……(內(nèi)心經(jīng)歷了各種自我勸說后)最終,我開啟了我的源碼學(xué)習(xí)之路。

于是我搜刮了一些常見的原理來進行學(xué)習(xí),我對 vue 源碼的第一步從 vue 的響應(yīng)式原理開始。

下面的這篇文章中,將記錄我學(xué)習(xí) vue 響應(yīng)式原理的總結(jié)。一起來了解一下吧~🙋?

一、組件化基礎(chǔ)

1、“很久以前”的組件化

(1)asp jsp php 時代

在很久以前,也就是大概第一批接觸網(wǎng)頁開發(fā)的程序員,在他們的那個年代其實就已經(jīng)有組件化了。

(2)nodejs

nodejs 比起 asp 、 jsp 和 php 來說,起步較晚,但是呢, nodejs 中也有類似的組件化,比如像 js 的模板引擎 ejs ,就可以實現(xiàn)組件化

我們來看下 ejs 是怎么實現(xiàn)組件化的?:

<!-- 個人信息 --> <div class = "right-item"><%- include('widgets/user-info', {userInfo:userData.userInfo,isMe:userData.isMe,amIFollowed:userData.amIFollowed,atCount:userData.atCount});%> </div> <!-- 用戶列表 --> <%- include('widgets/user-list', {count:userData.count,userList:userData.list });%>

通過以上代碼可以了解到, ejs 通過 <%- %> 的形式來定義一個組件,從而實現(xiàn)數(shù)據(jù)渲染。

雖說早期也有組件,但是對于傳統(tǒng)組件來說,也只是靜態(tài)渲染,并且它的更新還是要依賴于操作 DOM 。這樣子的話,用不用組件開發(fā)其實區(qū)別也不會差特別多。

因此,為了解決這個問題,就有了現(xiàn)在流行的 vue 和 react ,基于數(shù)據(jù)驅(qū)動視圖的開發(fā)。

2、數(shù)據(jù)驅(qū)動視圖(MVVM,setState)

(1)數(shù)據(jù)驅(qū)動視圖 - Vue MVVM

vue的組件化定義如下所示:

<template><div id="app"><imgalt="Vue logo"src="./assets/logo.png"><HelloWorldmsg="Welcome to your Vue.js App"/></div> </template>

引用官方的圖片,我們來講下 Vue 的 MVVM 。

所謂 MVVM ,即 Model-View-ViewModel

View視圖 ,也就是 DOM 。

Model模型 ,可以理解為 Vue 中組件里面的 data 。

那么這兩者之間,就通過 ViewModel 來做關(guān)聯(lián)。而 ViewModel 可以做的事情有很多,比如說像監(jiān)聽事件,監(jiān)聽指令等。當 Model 層的數(shù)據(jù)發(fā)生修改時,就可以通過 ViewModel ,來把數(shù)據(jù)渲染到 View 視圖層上。反之,當 View 層觸發(fā) DOM 事件時,就可以通過 ViewModel ,從而使得 Model 層實現(xiàn)數(shù)據(jù)的修改。

這就是 Vue 中的數(shù)據(jù)驅(qū)動視圖,通過修改 Model 層的數(shù)據(jù),來驅(qū)動到 View 的視圖中來。


了解完基本概念,我們用一段代碼來剖析 Vue 中的 MVVM 是怎么樣的。

<template><div id="app"><p @click="changeName">{{name}}</p><ul><li v-for="(item, index) in list" :key="index">{{item}}</li></ul><button @click="addItem">添加一項</button></div> </template> <script> export default {name:'app',data(){return{name:'vue',list:['a', 'b', 'c']}},methods:{changeName(){this.name = 'monday';},addItem(){this.list.push(`${Date.now()}`);}} } </script>

在上面的代碼中, template 部分就表示 view 層,而下面的 data 就表示 Model 層。之后呢,像 @click 這種點擊事件,點擊完之后觸發(fā)到具體的 methods ,這一部分就可以視為是 ViewModel 層,這樣的話,就可以理解為 ViewModel 層是連接 View 層和 Model 層的一個橋梁。

(2)數(shù)據(jù)驅(qū)動視圖 - React setState

React的組件化的定義如下所示:

function App(){return(<div className="App"><header className="AppHeader"><imgsrc={logo}className="App-logo"alt="logo"/><HelloWorldmsg="Welcome to Your React App"/></header></div>); }

React 通過 setState 去操作數(shù)據(jù)驅(qū)動視圖。這里不對 react 的數(shù)據(jù)驅(qū)動視圖進行細講,大家可以根據(jù)自身需求進行資料查詢~

(3)總結(jié)

vue 和 react 幫助我們通過數(shù)據(jù)去渲染視圖,這也就讓我們在做 vue 和 react 開發(fā)時,更多的是關(guān)注業(yè)務(wù)邏輯,而不像傳統(tǒng)組件一樣要一直去考慮 DOM 更新的問題。

二、Vue響應(yīng)式

1、vue的響應(yīng)式是什么

所謂 vue 的響應(yīng)式,即組件 data 的數(shù)據(jù)一旦變化,就會立刻觸發(fā)視圖的更新。實現(xiàn)數(shù)據(jù)驅(qū)動視圖的第一步,需要了解實現(xiàn)響應(yīng)式的一個核心 API ,即 Object.defineProperty 。

2、Object.defineProperty基本用法

我們用一段代碼來演示 Object.defineProperty 的用法,如下所示:

const data = {} const name = 'friday' Object.defineProperty(data, "name", {get:function () {console.log('get')return name},set: function (newVal) {console.log('set')name = newVal} })// 測試 console.log(data.name) //get friday data.name = 'monday' //set

通過上面的代碼可以看到,通過 Object.defineProperty ,我們可以實現(xiàn)對數(shù)據(jù)進行 get 和 set 操作,即獲取數(shù)據(jù)修改數(shù)據(jù)的操作,從而達到對數(shù)據(jù)進行響應(yīng)式的監(jiān)聽。

那 Object.defineProperty 又是如何實現(xiàn)響應(yīng)式的呢?接下來一起來一探究竟吧!

3、Oject.defineProperty實現(xiàn)響應(yīng)式

(1)監(jiān)聽對象

在了解響應(yīng)式之前,需要大家對 js 的數(shù)據(jù)類型和深拷貝有一個了解。這里我之前寫過一篇文章,如有需要可前往查看~

我們都知道 js 的數(shù)據(jù)類型有基本數(shù)據(jù)類型引用數(shù)據(jù)類型,接下來我們將來實現(xiàn)這兩種數(shù)據(jù)類型的響應(yīng)式監(jiān)聽。

基本數(shù)據(jù)類型:

// 觸發(fā)更新視圖 function updateView() {console.log('視圖更新') }// 重新定義屬性,監(jiān)聽起來 function defineReactive(target, key, value) {// 深度監(jiān)聽observer(value)// 核心 APIObject.defineProperty(target, key, {get() {return value},set(newValue) {if (newValue !== value) {// 深度監(jiān)聽observer(newValue)// 設(shè)置新值// 注意,value 一直在閉包中,此處設(shè)置完之后,再次 get 時也是會獲取最新的值value = newValue// 觸發(fā)更新視圖updateView()}}}) }// 監(jiān)聽對象屬性 function observer(target) {//判斷是基本數(shù)據(jù)類型 or 引用數(shù)據(jù)類型if (typeof target !== 'object' || target === null) {// 不是對象或數(shù)組return target}// 重新定義各個屬性(for in 也可以遍歷數(shù)組)for (let key in target) {defineReactive(target, key, target[key])} } // 準備數(shù)據(jù) const data = {name: 'monday',age: 20 }// 監(jiān)聽數(shù)據(jù) observer(data)// 測試 data.name = 'lisi' data.age = 18 console.log('name', data.name) console.log('age', data.age)

此時控制臺的打印效果如下:

從上圖可以看到,我們改變了兩個數(shù)據(jù)的值,數(shù)據(jù)也會實時更新。在控制臺中我們可以發(fā)現(xiàn),改變了兩個數(shù)據(jù)的值,同時也顯示出兩個“視圖更新”,至此,則說明這兩個數(shù)據(jù)監(jiān)聽成功

閱讀代碼我們可以發(fā)現(xiàn),當我們監(jiān)聽的數(shù)據(jù)是基本數(shù)據(jù)類型時,會直接返回 target 的值,并且視圖進行實時更新。

同時,需要注意的是, Object.defineProperty() 在新增屬性和刪除屬性時,數(shù)據(jù)是監(jiān)聽不到的

什么意思呢?我們來演示一下。

依據(jù)上面的代碼,我們再增加以下兩行內(nèi)容。

data.x = '100' // 新增屬性,監(jiān)聽不到 —— 用 Vue.set 解決 delete data.name // 刪除屬性,監(jiān)聽不到 —— 用 Vue.delete 解決

此時控制臺的打印結(jié)果如下:

細心的小伙伴已經(jīng)發(fā)現(xiàn),加上這兩行代碼后運行效果跟原來是一樣的。所以,我們可以得出結(jié)論,在用 Object.defineProperty() 新增和刪除屬性時,數(shù)據(jù)是監(jiān)聽不到的,這個時候即使數(shù)據(jù)修改了,視圖也監(jiān)聽不到對應(yīng)的數(shù)據(jù),也就沒有辦法進行視圖更新。


引用數(shù)據(jù)類型:

同樣,依據(jù)基本數(shù)據(jù)類型第一段的代碼,我們來監(jiān)聽引用數(shù)據(jù)類型的數(shù)據(jù)。測試代碼如下:

// 準備數(shù)據(jù) const data = {name: 'monday',age: 20,info: {address: '福州' // 需要深度監(jiān)聽},nums: ['打籃球', '出來玩', '打乒乓球'] }// 監(jiān)聽數(shù)據(jù) observer(data)// 測試 data.info.address = '上海' // 深度監(jiān)聽 data.nums.push('神游') // 監(jiān)聽數(shù)組

此時瀏覽器的打印結(jié)果如下:

我們可以發(fā)現(xiàn),只出現(xiàn)了一個視圖更新,沒有出現(xiàn)兩個。原因在于,對象 info 監(jiān)聽到了,但是數(shù)組 nums 并沒有監(jiān)聽到。這是為什么呢?

其實,從某種意義上來講, nums 雖然可以走到深度遍歷里面,但是呢, Object.defineProperty() 這個 API 本身是不具備監(jiān)聽數(shù)組能力的,所以我們需要加工一層,讓其可以擁有監(jiān)聽數(shù)組的能力。

(2)監(jiān)聽數(shù)組

要想讓 Object.defineProperty() 這個 API 擁有監(jiān)聽數(shù)組的能力,我們可以這么做。具體代碼如下:

// 觸發(fā)更新視圖 function updateView() {console.log('視圖更新') }// 重新定義數(shù)組原型 const oldArrayProperty = Array.prototype // 創(chuàng)建新對象,原型指向 oldArrayProperty ,再擴展新的方法不會影響原型 const arrProto = Object.create(oldArrayProperty); ['push', 'pop', 'shift', 'unshift', 'splice'].forEach(methodName => {arrProto[methodName] = function () {updateView() // 觸發(fā)視圖更新oldArrayProperty[methodName].call(this, ...arguments)// Array.prototype.push.call(this, ...arguments)} })// 重新定義屬性,監(jiān)聽起來 function defineReactive(target, key, value) {// 深度監(jiān)聽observer(value)// 核心 APIObject.defineProperty(target, key, {get() {return value},set(newValue) {if (newValue !== value) {// 深度監(jiān)聽observer(newValue)// 設(shè)置新值// 注意,value 一直在閉包中,此處設(shè)置完之后,再 get 時也是會獲取最新的值value = newValue// 觸發(fā)更新視圖updateView()}}}) }// 監(jiān)聽對象屬性 function observer(target) {if (typeof target !== 'object' || target === null) {// 不是對象或數(shù)組return target}// 污染全局的 Array 原型(如果直接定義在這里面,會直接污染全局)// Array.prototype.push = function () {// updateView()// ...// }if (Array.isArray(target)) {target.__proto__ = arrProto}// 重新定義各個屬性(for in 也可以遍歷數(shù)組)for (let key in target) {defineReactive(target, key, target[key])} }// 準備數(shù)據(jù) const data = {name: 'monday',age: 20,info: {address: '福州' // 需要深度監(jiān)聽},nums: ['打籃球', '出來玩', '打乒乓球'] }// 監(jiān)聽數(shù)據(jù) observer(data)// 測試 data.info.address = '上海' // 深度監(jiān)聽 data.nums.push('神游') // 監(jiān)聽數(shù)組

此時瀏覽器的打印效果如下:

我們可以看到,兩個數(shù)據(jù)對應(yīng)的視圖都更新了。通過對數(shù)組原型的重新定義,我們就讓 Object.defineProperty() 實現(xiàn)了監(jiān)聽數(shù)組的能力。

(3)幾個缺點

在讓 Object.defineProperty() 實現(xiàn)響應(yīng)式功能以后,我們來總結(jié)下其存在的幾個缺點:

1)深度監(jiān)聽,需要遞歸到底,一次性計算量大

在遍歷對象或數(shù)組時,需要進行深度監(jiān)聽,即需要遞歸到底,這會使得一次性計算量非常大。(這個問題在 vue3.0 中已經(jīng)解決,其解決原理是不一定要一次性遞歸,而是可以我們什么時候用,什么時候再遞歸。這個將放在后面的文章中講解)

2)無法監(jiān)聽新增屬性/刪除屬性

Object.defineProperty() 在進行新增屬性和刪除屬性時,視圖是無法進行更新的,也就是數(shù)據(jù)監(jiān)聽不到,這一點在平常的開發(fā)中需要特別注意!否則有時候我們在取數(shù)據(jù)時總會莫名其妙地都不知道自己錯在哪里。通常解決這個問題的方法是,使用 Vue.set 和 Vue.delete 來進行新增屬性刪除屬性,這樣就可以解決數(shù)據(jù)無法監(jiān)聽的問題。

3)無法原生監(jiān)聽數(shù)組,需要特殊處理

Object.defineProperty() 這個 API 本身無法監(jiān)聽原生數(shù)組,需要通過重新定義數(shù)組原型的方式,來對數(shù)組進行數(shù)據(jù)監(jiān)聽。

四、結(jié)束語

對于 vue2.x 的響應(yīng)式原理講到這里就結(jié)束啦!從上面的分析中我們可以發(fā)現(xiàn), Object.defineProperty() 有它一定的好用之處,但同時也有一些缺點存在。因此 Vue3.0 用了 Proxy 來解決上述缺點中存在的問題,但是呢, proxy 到現(xiàn)在其實也還沒有推廣開來,因為 proxy 有兼容性的問題存在,如無法兼容 IE11 等問題,且 proxy 無法 polyfill ,所以 vue2.x 很長一段時間內(nèi)應(yīng)該還會存在。因此,對于 vue2.x 和 vue3.0 來說,這兩者都是得學(xué)的,而不是說出了 vue3.0 就不學(xué) vue2.x 了,對于這兩者來說,更多的是相輔相成的一個結(jié)果。

閑談到此結(jié)束,對于 vue 原理的學(xué)習(xí)有深深感受到造輪子的快樂,但是啃源碼在開始學(xué)習(xí)時確實會比較枯燥。希望再接再厲,爭取啃下更多 vue 的源碼,讀懂更多原理!

  • 關(guān)注公眾號 星期一研究室 ,不定期分享學(xué)習(xí)干貨,學(xué)習(xí)路上不迷路~
  • 如果這篇文章對你有用,記得點個贊加個關(guān)注再走哦~

總結(jié)

以上是生活随笔為你收集整理的手把手教你剖析vue响应式原理,监听数据不再迷茫的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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

主站蜘蛛池模板: 91一区二区三区四区 | 97超碰碰碰 | 草草视频在线免费观看 | 黄色免费在线观看网站 | 人人妻人人澡人人爽精品日本 | 天天草av | 欧美黑人添添高潮a片www | 激情综合五月网 | 男女黄床上色视频免费的软件 | 久久精品国产99国产 | 欧美另类极品videosbest使用方法 | 一个色综合导航 | 高清中文字幕mv的电影 | 在线观看a网站 | 国产99久久九九精品无码 | 白嫩情侣偷拍呻吟刺激 | 男人av网| 男人和女人在床的app | 天天干天天做天天操 | 国产精品无套 | 亚洲精品v天堂中文字幕 | 欧美精品一区二区三区蜜臀 | 欧美日韩视频网站 | 成年人网站在线免费观看 | 奇米影视一区二区三区 | 成人免费视频国产免费 | 亚洲国产欧美自拍 | 91一区二区在线观看 | 亚洲在线观看视频 | 亚洲成人看片 | 国产免费美女 | a天堂视频在线观看 | 国产极品999 | 草碰在线| 日本久久成人 | 中文字幕2018 | 国产一级爽片 | 日本婷婷 | 天天艹av | 97超级碰碰 | 亚洲人毛茸茸 | 台湾佬中文字幕 | 成人在线观看91 | 亚洲一区二区黄片 | 日韩精品在线视频免费观看 | 99自拍视频 | 欧美一区影院 | 69视频在线播放 | 欧美z○zo重口另类黄 | 精品日韩一区二区三区四区 | 国产精美视频 | 欧美日本韩国一区 | 美女网站全黄 | 日韩欧美在线视频 | 天堂在线8 | 黄网站在线观看 | 一区二区三区网 | 日本啪啪网 | china国产乱xxxxx绿帽 | av免费视屏 | 久久久老熟女一区二区三区91 | 无限资源日本好片 | 日韩小视频在线 | 欧美日韩一卡 | 日本福利一区二区 | 亚洲欧洲一区 | 精品国产网站 | 青青草精品在线视频 | 国产精品视频久久久久久 | 中文字幕黄色片 | 91九色高潮 | 日韩毛片网站 | 久久久久久久无码 | 99免费精品视频 | 91看片黄色 | 人妻丰满熟妇av无码区不卡 | 欧美一级视频在线观看 | 国产精品亲子伦对白 | 青青青手机视频在线观看 | 亚洲第一大网站 | 中文一区二区在线观看 | 国产a级片| 色偷偷视频| 玩偶姐姐在线看 | 日韩色道 | 少妇熟女视频一区二区三区 | 天堂网视频在线 | 明日花绮罗高潮无打码 | 毛片大全免费看 | 欧美18av| 亚洲av无码乱码国产麻豆 | 人妻 日韩精品 中文字幕 | 97成人人妻一区二区三区 | 综合五月天 | 国产99久久久欧美黑人 | 国产精品资源 | 久久久久久9999 | 99热18| 中国av在线播放 |