vue?Proxy數(shù)據(jù)代理進(jìn)行校驗(yàn)部分源碼實(shí)例解析
initProxy
數(shù)據(jù)攔截的思想除了為構(gòu)建響應(yīng)式系統(tǒng)準(zhǔn)備,它也可以為數(shù)據(jù)進(jìn)行篩選過濾,我們接著往下看初始化的代碼,在合并選項(xiàng)后,vue接下來會(huì)為vm實(shí)例設(shè)置一層代理,這層代理可以為vue在模板渲染時(shí)進(jìn)行一層數(shù)據(jù)篩選
Vue.prototype._init = function(options) { // 選項(xiàng)合并 ... { // 對vm實(shí)例進(jìn)行一層代理 initProxy(vm); } ... }
initProxy
// 代理函數(shù) var initProxy = function initProxy (vm) { //是否支持Proxy if (hasProxy) { var options = vm.$options; //當(dāng)使用類似webpack這樣的打包工具時(shí),通常會(huì)使用vue-loader插件進(jìn)行模板的編譯,這個(gè)時(shí)候options.render是存在的,并且_withStripped的屬性也會(huì)設(shè)置為true(關(guān)于編譯版本和運(yùn)行時(shí)版本的區(qū)別可以參考后面章節(jié)),所以此時(shí)代理的選項(xiàng)是hasHandler //在其他場景下,代理的選項(xiàng)是getHandler var handlers = options.render && options.render._withStripped ? getHandler : hasHandler; // 代理vm實(shí)例到vm屬性_renderProxy vm._renderProxy = new Proxy(vm, handlers); } else { vm._renderProxy = vm; } };
hasProxy
var hasProxy = typeof Proxy !== 'undefined' && isNative(Proxy);
hasHandler
var hasHandler = { // key in obj或者with作用域時(shí),會(huì)觸發(fā)has的鉤子 has: function has (target, key) { ··· } };
觸發(fā)代理
源碼中vm._renderProxy的使用出現(xiàn)在Vue實(shí)例的_render方法中,Vue.prototype._render是將渲染函數(shù)轉(zhuǎn)換成Virtual DOM的方法,這部分是關(guān)于實(shí)例的掛載和模板引擎的解析
當(dāng)我們調(diào)用render函數(shù)時(shí),代理的vm._renderProxy對象便會(huì)訪問到
而這個(gè)render函數(shù)就是包裝成with的執(zhí)行語句,在執(zhí)行with語句的過程中,該作用域下變量的訪問都會(huì)觸發(fā)has鉤子,這也是模板渲染時(shí)之所有會(huì)觸發(fā)代理攔截的原因
之所以會(huì)觸發(fā)數(shù)據(jù)代理攔截是因?yàn)槟0逯惺褂昧俗兞?,例?lt;div>{{message}}}
Vue.prototype._render = function () { ··· // 調(diào)用vm._renderProxy vnode = render.call(vm._renderProxy, vm.$createElement); } ========================================= var vm = new Vue({ el: '#app' }) console.log(vm.$options.render) ???????//輸出, 模板渲染使用with語句 ? anonymous() { with(this){return _c('div',{attrs:{"id":"app"}},[_v(_s(message)+_s(_test))])} }
數(shù)據(jù)過濾
通過data選項(xiàng)去設(shè)置實(shí)例數(shù)據(jù),那么這些數(shù)據(jù)可以隨著個(gè)人的習(xí)慣任意命名嗎?顯然不是的,如果你使用js的關(guān)鍵字(像Object,Array,NaN)去命名,這是不被允許的。另一方面,Vue源碼內(nèi)部使用了以$,_作為開頭的內(nèi)部變量,所以以$,_開頭的變量名也是不被允許的,這就構(gòu)成了數(shù)據(jù)過濾監(jiān)測的前提。
var hasHandler = { has: function has (target, key) { var has = key in target; // isAllowed用來判斷模板上出現(xiàn)的變量是否合法。 var isAllowed = allowedGlobals(key) || (typeof key === 'string' && key.charAt(0) === '_' && !(key in target.$data)); // _和$開頭的變量不允許出現(xiàn)在定義的數(shù)據(jù)中,因?yàn)樗莢ue內(nèi)部保留屬性的開頭。 // 1. warnReservedPrefix: 警告不能以$ _開頭的變量 // 2. warnNonPresent: 警告模板出現(xiàn)的變量在vue實(shí)例中未定義 //has判斷是否是target對象中的變量 if (!has && !isAllowed) { if (key in target.$data) { warnReservedPrefix(target, key); } else { warnNonPresent(target, key); } } return has || !isAllowed } }; // 模板中允許出現(xiàn)的非vue實(shí)例定義的變量 var allowedGlobals = makeMap( 'Infinity,undefined,NaN,isFinite,isNaN,' + 'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' + 'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,' + 'require' // for Webpack/Browserify );
在瀏覽器不支持proxy的情況下的數(shù)據(jù)過濾
在沒有經(jīng)過代理的情況下,使用_開頭的變量依舊會(huì) 報(bào)錯(cuò),但是它變成了js語言層面的錯(cuò)誤。但是這個(gè)報(bào)錯(cuò)無法在Vue這一層知道錯(cuò)誤的詳細(xì)信息,而這就是能使用Proxy的好處。
在初始化數(shù)據(jù)階段,Vue已經(jīng)為數(shù)據(jù)進(jìn)行了一層篩選的代理。具體看initData對數(shù)據(jù)的代理
有了isReserved的篩選,即使this._data._test存在,我們依舊無法在訪問this._test時(shí)拿到_test變量
function initData(vm) { vm._data = typeof data === 'function' ? getData(data, vm) : data || {} if (!isReserved(key)) { // 數(shù)據(jù)代理,用戶可直接通過vm實(shí)例獲取返回data數(shù)據(jù) proxy(vm, "_data", key); } } function isReserved (str) { var c = (str + '').charCodeAt(0); // 首字符是$, _的字符串 return c === 0x24 || c === 0x5F }
proxy
function proxy (target, sourceKey, key) { sharedPropertyDefinition.get = function proxyGetter () { // 當(dāng)訪問this[key]時(shí),會(huì)代理訪問this._data[key]的值 return this[sourceKey][key] }; sharedPropertyDefinition.set = function proxySetter (val) { this[sourceKey][key] = val; }; Object.defineProperty(target, key, sharedPropertyDefinition); }
總結(jié)
到此這篇關(guān)于vue Proxy數(shù)據(jù)代理進(jìn)行校驗(yàn)部分源碼解析的文章就介紹到這了,更多相關(guān)vue Proxy數(shù)據(jù)代理校驗(yàn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue3封裝組件完整實(shí)例(帶回調(diào)事件)
Vue.js已成為現(xiàn)代Web開發(fā)中不可或缺的技術(shù)之一,雖然Vue.js的一些基礎(chǔ)概念和語法比較易學(xué),但深入挖掘Vue.js的核心概念和功能需要更多的實(shí)踐,下面這篇文章主要給大家介紹了關(guān)于Vue3封裝組件(帶回調(diào)事件)的相關(guān)資料,需要的朋友可以參考下2023-06-06解決iView中時(shí)間控件選擇的時(shí)間總是少一天的問題
下面小編就為大家分享一篇解決iView中時(shí)間控件選擇的時(shí)間總是少一天的問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-03-03Vue+Video.js實(shí)現(xiàn)視頻抽幀并返回抽幀圖片Base64
這篇文章主要為大家詳細(xì)介紹了Vue如何利用Video.js實(shí)現(xiàn)視頻抽幀并返回抽幀圖片Base64,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下2024-01-01Vue的hover/click事件如何動(dòng)態(tài)改變顏色和背景色
這篇文章主要介紹了Vue的hover/click事件如何動(dòng)態(tài)改變顏色和背景色問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11