關(guān)于vue2響應(yīng)式缺陷的問題
vue2響應(yīng)式缺陷
響應(yīng)式 : 數(shù)據(jù)改變 ==> 視圖跟著改變
vue2響應(yīng)式缺陷
1.對象新增的屬性沒有響應(yīng)式
對象,新增屬性b,修改b的值,值改變但視圖并未更新
解決方案 : 使用vue提供的 api $set(對象,屬性名,值) 效果如屬性c
2.數(shù)組的部分操作沒有響應(yīng)式
數(shù)組中有7種操作有響應(yīng)式
array.pop()
array.push()
array.shift()
array.unshift()
array.sort()
arry.reverse()
array.splice()
以上7中API會修改原數(shù)組(vue2的內(nèi)部重寫了這7個API)
其他的操作都不會有響應(yīng)式
示例:
1.修改數(shù)組的第一個元素的值
// 直接通過下標(biāo)來修改,沒有響應(yīng)式 fn1() { this.arr[0] = 100 }
通過下標(biāo)直接賦值,沒有響應(yīng)式
2.修改數(shù)組的長度為0
//修改數(shù)組的length fn2 () { this.arr.length = 0 }
修改數(shù)組的length,沒有響應(yīng)式
如何修改數(shù)組的值有響應(yīng)式
fn1 () { // 方法1: 先刪除,再添加 this.arr.splice(0,1,100) }, fn2 () { // 方法2: $set this.$set(this.arr, "0", 100) }
vue2與vue3的響應(yīng)式原理
給大家分享一下Vue2和Vue3的響應(yīng)式原理;說到響應(yīng)式無非就是監(jiān)聽屬性的獲取,修改及刪除...,了解邏輯之后再去實現(xiàn)底層代碼豈不是快了許多=_=
vue2響應(yīng)式
原理:利用defineReactive方法,通過defineProperty對屬性進(jìn)行劫持,數(shù)組則是通過重寫其方法來進(jìn)行劫持,每個屬性值都擁有自己的dep屬性,用來存取所依賴的watch,當(dāng)數(shù)據(jù)發(fā)生改變時,觸發(fā)相應(yīng)的watch去更新數(shù)據(jù)
代碼實現(xiàn):
const { arrayMethods } = require('./array') class Observer { constructor(value) { Object.defineProperty(value, '__ob__', { value: this, enumerable: false, writable: true, configurable: true }) if(Array.isArray(value)) { value.__proto__ = arrayMethods this.observeArray(value) } else { this.walk(value) } } walk(data) { let keys = Object.keys(data) for(let i = 0; i < keys.length; i++) { const key = keys[i] const value = data[key] defineReactive(data, key, value) } } observeArray(items) { for(let i = 0; i < items.length; i++) { observe(items[i]) } } } function defineReactive(data, key, value) { const childOb = observe(value) const dep = new Dep() Object.defineProperty(data, key, { get() { console.log('獲取值') if (Dep.target) { dep.depend() if (childOb) { childOb.dep.depend() if (Array.isArray(value)) { dependArray(value) } } } return value }, set(newVal) { if (newVal === value) return observe(newVal) value = newVal dep.notify() } }) } function observe(value) { if (Object.prototype.toString.call(value) === '[object Object]' || Array.isArray(value)) { return new Observer(value) } } function dependArray(value) { for(let e, i = 0, l = value.length; i < l; i++) { e = value[i] e && e.__ob__ && e.__ob__.dep.depend() if (Array.isArray(e)) { dependArray(e) } } } // array.js const arrayProto = Array.prototype const arrayMethods = Object.create(arrayProto) const methodsToPatch = [ 'push', 'pop', 'shift', 'unshift', 'splice', 'reverse', 'sort' ] methodsToPatch.forEach(method => { arrayMethods[method] = function (...args) { const result = arrayProto[method].apply(this, args) const ob = this.__ob__ var inserted switch (method) { case 'push': case 'unshift': inserted = args break; case 'splice': inserted = args.slice(2) default: break; } if (inserted) ob.observeArray(inserted) ob.dep.notify() return result } })
但是呢,Vue2的響應(yīng)式還存在一些缺陷:1.對象新增屬性,刪除屬性界面不會更新 2.通過數(shù)組下標(biāo)修改數(shù)組內(nèi)容界面不會更新
原因:1.Vue 無法檢測 property 的添加或移除。由于 Vue 會在初始化實例時對 property 執(zhí)行 getter/setter 轉(zhuǎn)化,所以 property 必須在 data 對象上存在才能讓 Vue 將它轉(zhuǎn)換為響應(yīng)式的
2.通過數(shù)組下標(biāo)修改數(shù)組不會觸發(fā)響應(yīng),因為尤雨溪用了重寫數(shù)組的方法來實現(xiàn)數(shù)據(jù)的響應(yīng)綁定,當(dāng)vue遇到push pop shift unshift splice sort reverse 的時候數(shù)組才會改變
解決方案:1.對象:對象新增屬性無法更新視圖,通過Vue.$set(obj,key,value),組件中通過this.$set(obj,key,value)
2.數(shù)組:通過數(shù)組下標(biāo)修改數(shù)組不會觸發(fā)視圖更新,可以通過Vue.$set(obj,key,value),也可以通過push pop shift unshift splice sort reverse方法來實現(xiàn)響應(yīng)
Vue3的響應(yīng)式彌補了Vue2響應(yīng)式的缺陷,并且還帶來了許多優(yōu)化,下面讓我們來了解一下Vue3響應(yīng)式的基本雛形
vue3響應(yīng)式雛形
原理:利用了Proxy和Reflect來代替Vue2的Object.defineProperty()方法來重寫響應(yīng)式
這只是基本的代碼:
let person = { name: '張三', age: 18 } const p = new Proxy(person, { get(target, propName) { console.log(`我的${propName}值被獲取了`); return Reflect.get(target, propName) }, set(target, propName, value) { console.log(`我的${propName}值被修改了`); Reflect.set(target, propName, value) }, deleteProperty(target, propName) { console.log(`我的${propName}值被刪除了`); Reflect.deleteProperty(target, propName) } })
target指的是整個person,propName指的是person中的某個屬性,value指的是新值。
運行結(jié)果:
vue3的響應(yīng)式相較于vue2的優(yōu)勢
用 Proxy 和 Reflect 來代替 vue2 中的 Object.definepeoperty()方法來重寫響應(yīng)式
vue3 中可以監(jiān)聽動態(tài)新增的屬性
vue3 中可以監(jiān)聽刪除的屬性
vue3 中可以監(jiān)聽數(shù)組的索引和 length 屬性
代碼的執(zhí)行效果更快
Proxy 可以直接監(jiān)聽對象而非屬性
Proxy 可以直接監(jiān)聽數(shù)組的變化
Proxy 有多達(dá) 13 種攔截方法,不限于 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具備的
Proxy 返回的是一個新對象,我們可以只操作新的對象達(dá)到目的,而 Object.defineProperty 只能遍歷對象屬性直接修改
Proxy 不需要初始化的時候遍歷所有屬性,另外有多層屬性嵌套的話,只有訪問某個屬性的時候,才會遞歸處理下一級的屬性
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
vue-treeselect及el-tree點擊節(jié)點獲取上級節(jié)點的數(shù)據(jù)方式
這篇文章主要介紹了vue-treeselect及el-tree點擊節(jié)點獲取上級節(jié)點的數(shù)據(jù)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07Vue3使用路由及配置vite.alias簡化導(dǎo)入寫法的過程詳解
這篇文章主要介紹了Vue3使用路由及配置vite.alias簡化導(dǎo)入寫法,本文通過實例代碼給大家講解的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-11-11淺談vue項目用到的mock數(shù)據(jù)接口的兩種方式
這篇文章主要介紹了淺談vue項目用到的mock數(shù)據(jù)接口的兩種方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10