文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

vue Proxy数据代理进行校验部分源码实例解析

2024-04-02 19:55

关注

initProxy

数据拦截的思想除了为构建响应式系统准备,它也可以为数据进行筛选过滤,我们接着往下看初始化的代码,在合并选项后,vue接下来会为vm实例设置一层代理,这层代理可以为vue在模板渲染时进行一层数据筛选

Vue.prototype._init = function(options) {
    // 选项合并
    ...
    {
        // 对vm实例进行一层代理
        initProxy(vm);
    }
    ...
}

initProxy

// 代理函数
var initProxy = function initProxy (vm) {
    //是否支持Proxy
    if (hasProxy) {
        var options = vm.$options;
        //当使用类似webpack这样的打包工具时,通常会使用vue-loader插件进行模板的编译,这个时候options.render是存在的,并且_withStripped的属性也会设置为true(关于编译版本和运行时版本的区别可以参考后面章节),所以此时代理的选项是hasHandler
        //在其他场景下,代理的选项是getHandler
        var handlers = options.render && options.render._withStripped
            ? getHandler
            : hasHandler;
        // 代理vm实例到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作用域时,会触发has的钩子
    has: function has (target, key) {
        ···
    }
};

触发代理

源码中vm._renderProxy的使用出现在Vue实例的_render方法中,Vue.prototype._render是将渲染函数转换成Virtual DOM的方法,这部分是关于实例的挂载和模板引擎的解析

当我们调用render函数时,代理的vm._renderProxy对象便会访问到

而这个render函数就是包装成with的执行语句,在执行with语句的过程中,该作用域下变量的访问都会触发has钩子,这也是模板渲染时之所有会触发代理拦截的原因

之所以会触发数据代理拦截是因为模板中使用了变量,例如<div>{{message}}}

Vue.prototype._render = function () {
    ···
    // 调用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))])}
}

数据过滤

通过data选项去设置实例数据,那么这些数据可以随着个人的习惯任意命名吗?显然不是的,如果你使用js的关键字(像Object,Array,NaN)去命名,这是不被允许的。另一方面,Vue源码内部使用了以$,_作为开头的内部变量,所以以$,_开头的变量名也是不被允许的,这就构成了数据过滤监测的前提。

var hasHandler = {
    has: function has (target, key) {
        var has = key in target;
        // isAllowed用来判断模板上出现的变量是否合法。
        var isAllowed = allowedGlobals(key) ||
            (typeof key === 'string' && key.charAt(0) === '_' && !(key in target.$data));
            // _和$开头的变量不允许出现在定义的数据中,因为他是vue内部保留属性的开头。
            
        // 1. warnReservedPrefix: 警告不能以$ _开头的变量
        // 2. warnNonPresent: 警告模板出现的变量在vue实例中未定义
        //has判断是否是target对象中的变量
        if (!has && !isAllowed) {
            if (key in target.$data) { warnReservedPrefix(target, key); }
            else { warnNonPresent(target, key); }
        }
        return has || !isAllowed
    }
};
// 模板中允许出现的非vue实例定义的变量
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的情况下的数据过滤

在没有经过代理的情况下,使用_开头的变量依旧会 报错,但是它变成了js语言层面的错误。但是这个报错无法在Vue这一层知道错误的详细信息,而这就是能使用Proxy的好处。

在初始化数据阶段,Vue已经为数据进行了一层筛选的代理。具体看initData对数据的代理

有了isReserved的筛选,即使this._data._test存在,我们依旧无法在访问this._test时拿到_test变量

function initData(vm) {
    vm._data = typeof data === 'function' ? getData(data, vm) : data || {}
    if (!isReserved(key)) {
        // 数据代理,用户可直接通过vm实例获取返回data数据
        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 () {
        // 当访问this[key]时,会代理访问this._data[key]的值
        return this[sourceKey][key]
    };
    sharedPropertyDefinition.set = function proxySetter (val) {
        this[sourceKey][key] = val;
    };
    Object.defineProperty(target, key, sharedPropertyDefinition);
}

总结 

到此这篇关于vue Proxy数据代理进行校验部分源码解析的文章就介绍到这了,更多相关vue Proxy数据代理校验内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-前端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯