Vue數(shù)據(jù)代理的實(shí)現(xiàn)流程逐步講解
一,前言
上篇,主要介紹了 Vue 數(shù)據(jù)初始化流程中,數(shù)組類型的數(shù)據(jù)劫持是如何實(shí)現(xiàn)的,核心思路如下:
出于對(duì)性能的考慮,Vue 沒有對(duì)數(shù)組采用 Object.defineProperty 進(jìn)行遞歸劫持,而是對(duì)能夠?qū)е略瓟?shù)組變化的 7 個(gè)方法進(jìn)行了攔截和重寫,實(shí)現(xiàn)了對(duì)數(shù)組的數(shù)據(jù)劫持
至此,已經(jīng)完成了對(duì)響應(yīng)式數(shù)據(jù)(對(duì)象和數(shù)組)的劫持(深層劫持)操作
本篇,繼續(xù)介紹 Vue 數(shù)據(jù)初始化流程中, Vue 實(shí)例上數(shù)據(jù)代理的實(shí)現(xiàn)
二,數(shù)據(jù)代理的實(shí)現(xiàn)
1,Vue 是如何操作數(shù)據(jù)的
在 Vue 中,是可以在外部直接通過 vm 實(shí)例進(jìn)行數(shù)據(jù)訪問和操作:
let vm = new Vue({
el: '#app',
data() {
return { message: 'Hello Vue', obj: { key: "val" }, arr:[1,2,3]}
}
});
console.log(vm.message)
console.log(vm.arr.push(4))
拋出問題:vm.message 等價(jià)于 $options.data.message,是如何實(shí)現(xiàn)的?
2,當(dāng)前是如何操作數(shù)據(jù)的
當(dāng)前代碼,外部的 vm 實(shí)例只能拿到 vm. o p t i o n s ,拿到 d a t a 需要 v m . options,拿到 data 需要 vm. options,拿到data需要vm.options.data
// src/state.js#initData
function initData(vm) {
let data = vm.$options.data;
data = isFunction(data) ? data.call(vm) : data;
observe(data);
data.message
data.arr.push(4);
}
要想實(shí)現(xiàn) vm.message 和 $options.data.message 等效
相當(dāng)于將 vm 實(shí)例操作代理到 $options.data 上,即實(shí)現(xiàn)數(shù)據(jù)代理
3,數(shù)據(jù)代理的思路
為了讓外部的 vm 實(shí)例能夠拿到觀測(cè)后的 data,將處理后的 data 直接掛載到 vm 上
// src/state.js#initData
function initData(vm) {
let data = vm.$options.data;
data = vm._data = isFunction(data) ? data.call(vm) : data;
observe(data);
}
這樣,vm 實(shí)例就能夠在外部通過 vm._data.message 獲取到 data.message
接下來,再做一次代理,將 vm 實(shí)例操作(vm.message),代理到 vm._data 上即可
4,數(shù)據(jù)代理的實(shí)現(xiàn)
通過 Object.defineProperty 對(duì) _data 中的數(shù)據(jù)操作進(jìn)行劫持
即:vm.message 在 vm 實(shí)例上取值時(shí),將它代理到 vm._data 上取值
// src/state.js#initData
function initData(vm) {
let data = vm.$options.data;
data = vm._data = isFunction(data) ? data.call(vm) : data;
observe(data);
// 當(dāng) vm.message 在 vm 實(shí)例上取值時(shí),將它代理到vm._data上去取
for(let key in data){
Proxy(vm, key, '_data')
}
}
// src/state.js#Proxy
/**
* 代理方法
* 當(dāng)取 vm.key 時(shí),將它代理到 vm._data上去取
* @param {*} vm vm 實(shí)例
* @param {*} key 屬性名
* @param {*} source 代理目標(biāo),這里是vm._data
*/
function Proxy(vm, key, source) {
Object.defineProperty(vm, key, {
get(){
return vm[source][key]
},
set(newValue){
vm[source][key] = newValue;
}
})
}
5,數(shù)據(jù)代理的測(cè)試
let vm = new Vue({
el: '#app',
data() {
return { message: 'Hello Vue', obj: { key: "val" }, arr:[1,2,3]}
}
});
console.log(vm)
console.log(vm.message)

觀察打印結(jié)果:
獲取 vm 實(shí)例時(shí),會(huì)通過 get 方法將 _data 全部屬性打印出來
當(dāng)前 vm 實(shí)例上,包含 data 全部屬性及對(duì)應(yīng)的 get、set 方法
這樣,就實(shí)現(xiàn)了數(shù)據(jù)代理:
當(dāng)從 vm 實(shí)例取值時(shí),就會(huì)被代理到 vm._data 取值
三,結(jié)尾
本篇主要介紹了 Vue 數(shù)據(jù)初始化流程中,Vue 實(shí)例上數(shù)據(jù)代理的實(shí)現(xiàn),核心思路如下:
- 將 data 暴露在 vm._data 實(shí)例屬性上
- 利用 Object.defineProperty 將 vm.xxx 操作代理到 vm._data 上
到此這篇關(guān)于Vue數(shù)據(jù)代理的實(shí)現(xiàn)流程逐步講解的文章就介紹到這了,更多相關(guān)Vue數(shù)據(jù)代理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue3+vite動(dòng)態(tài)加載路由,本地路由和線上路由匹配方式
這篇文章主要介紹了vue3+vite動(dòng)態(tài)加載路由,本地路由和線上路由匹配方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06
使用vue.js在頁面內(nèi)組件監(jiān)聽scroll事件的方法
今天小編就為大家分享一篇使用vue.js在頁面內(nèi)組件監(jiān)聽scroll事件的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-09-09
vue v-for 點(diǎn)擊當(dāng)前行,獲取當(dāng)前行數(shù)據(jù)及event當(dāng)前事件對(duì)象的操作
這篇文章主要介紹了vue v-for 點(diǎn)擊當(dāng)前行,獲取當(dāng)前行數(shù)據(jù)及event當(dāng)前事件對(duì)象的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-09-09
vue+element實(shí)現(xiàn)動(dòng)態(tài)加載表單
這篇文章主要為大家詳細(xì)介紹了vue+element實(shí)現(xiàn)動(dòng)態(tài)加載表單,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-12-12
vue中的模態(tài)對(duì)話框組件實(shí)現(xiàn)過程
這篇文章主要介紹了vue中的模態(tài)對(duì)話框組件實(shí)現(xiàn)過程,通過template定義組件,并添加相應(yīng)的對(duì)話框樣式,需要的朋友可以參考下2018-05-05
Vue3項(xiàng)目中優(yōu)雅實(shí)現(xiàn)微信授權(quán)登錄的方法
用戶在微信端中訪問第三方網(wǎng)頁,可以通過微信網(wǎng)頁授權(quán)機(jī)制獲取用戶的基本信息,進(jìn)而實(shí)現(xiàn)所需要的業(yè)務(wù)邏輯,這篇文章主要給大家介紹了關(guān)于Vue3項(xiàng)目中優(yōu)雅實(shí)現(xiàn)微信授權(quán)登錄的相關(guān)資料,需要的朋友可以參考下2021-09-09

