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

目录
  • initProxy
  • 触发代理
  • 数据过滤
  • 总结

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数据代理校验内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Vue使用Proxy代理后仍无法生效的解决

    vue.js 配置了前端代理却未能生效 记录一下最近踩得小坑: 配置完代理后请一定重新执行(重要,非常重要!) npm run dev 若重新执行命令后,代理仍为生效,请按下方步骤进行检查: 检查index.js文件中的代理是否配置正确,示例如下: proxyTable: { '/api': { //代理标识 target: 'http://xxx.xxx.xxx',//指向的实际地址 changeOrigin: true, // 允许跨域 pathRewrite: { // 标识替换 // 原

  • Vue中如何实现proxy代理

    Vue 框架开发的时候,会遇到跨域的问题,可在config/index.js 里配置proxyTable内容,使用proxy 代理. // config/index.js 文件 proxyTable: { '/api': { target: 'http://192.168.149.90:8080/', // 设置你调用的接口域名和端口号 changeOrigin: true, // 跨域 pathRewrite: { '^/api': '/' } } }, 这里理解成用'/api'代替targe

  • webpack+vue-cil 中proxyTable配置接口地址代理操作

    在项目开发的时候,接口联调的时候一般都是同域名下,且不存在跨域的情况下进行接口联调,但是当我们现在使用vue-cli进行项目打包的时候,我们在本地启动服务器后,比如本地开发服务下是 http://localhost:8080 这样的访问页面,但是我们的接口地址是 http://xxxx.com/save/index 这样的接口地址,我们这样直接使用会存在跨域的请求,导致接口请求不成功,因此我们需要在打包的时候配置一下,我们进入 config/index.js 代码下如下配置即可: dev: {

  • vue cli3 配置proxy代理无效的解决

    vue cli3 创建的vue项目配置开发环境代理无效,网上的各种配置都试了,还是不行,最后终于试出来一种配置方法 vue.config.js配置如下内容(不要配置任何多余的选项,什么changOrigin pathRewrite 之类的东西都不要配): module.exports = { devServer: { proxy:"http://127.0.0.1:8081", port: 8085 } } axios访问的时候不要配置任何东西,axios里访问的url不需要加任何前缀

  • Vue项目配置跨域访问和代理proxy设置方式

    在vue单页应用项目开发时,避免不了要请求后端,这时通常就会出现跨域问题.有2种常用的解决方案 后端设置允许跨域访问 前端通过代理进行访问后端 下面我们只说说如何配置vue-cli代理访问: vue-cli代理 最简单就是配置vue conifg进行实现 下面配置3个请求的后端,分别是: 请求http://localhost:4201/adminapi/*会代理请求http://localhost:8180/* 请求http://localhost:4201/portalapi/*会代理请求ht

  • vue3简易实现proxy代理实例详解

    vue3 简易实现proxy代理 1.基础数据 const state = reactive({ name: 'cld', age: 26, like: 'paint' }); console.log("获取更改age前的值", state.age); state.age = 28; console.log("获取更改age后的值", state.age); 核心逻辑 reactive export function reactive (target) { // 创

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

    目录 initProxy 触发代理 数据过滤 总结 initProxy 数据拦截的思想除了为构建响应式系统准备,它也可以为数据进行筛选过滤,我们接着往下看初始化的代码,在合并选项后,vue接下来会为vm实例设置一层代理,这层代理可以为vue在模板渲染时进行一层数据筛选 Vue.prototype._init = function(options) { // 选项合并 ... { // 对vm实例进行一层代理 initProxy(vm); } ... } initProxy // 代理函数 var

  • LRU算法及Apache LRUMap源码实例解析

    目录 1. 什么是LRU 1.1 自定义实现LRU的要求 1.2 Apache LRUMap示例 1.2.1 pom依赖 1.2.2 demo 2. 源码解析 2.1 设计 2.2 数据结构 2.3 方法解析put get remove 2.3.1 get方法 2.3.2 remove方法 2.3.3 put方法 3. 总结 1. 什么是LRU LRU(least recently used) : 最近最少使用 LRU就是一种经典的算法,在容器中,对元素定义一个最后使用时间,当新的元素写入的时候

  • spring cloud openfeign 源码实例解析

    一.读取注解信息 入口 import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication @EnableFeignClients public class

  • PHP中实现汉字转区位码应用源码实例解析

    复制代码 代码如下: <?php global $PHP_SELF; //echo $PHP_SELF; $t1=$_POST['textfield1']; $t2=$_POST['textfield2']; $t3=$_POST['textfield3']; $t4=$_POST['textfield4']; // 汉字--区位码 if($t1!=""){ $t2= sprintf("%02d%02d",ord($t1[0])-160,ord($t1[1])

  • VUE的数据代理与事件详解

    目录 回顾Object.defineProperty方法 何为数据代理 Vue中的数据代理 事件的基本使用 事件的修饰符 键盘事件 总结 回顾Object.defineProperty方法 <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>回顾Object.defineproperty方法</title> </head> <

  • vue loadmore 组件滑动加载更多源码解析

    上一篇讲到在项目中使用上拉加载更多组件,但是由于实际项目开发中由于需求变更或者说在webview中上拉加载有些机型在上拉时候会把webview也一起上拉导致上拉加载不灵敏等问题,我们有时候也会换成滑动到底部自动加载的功能. 既然都是加载更多,很多代码思想势必相似,主要区别在于上拉和滑动到底部这个操作上,所以,我们需要注意: 上拉加载是point指针touch触摸事件,现在因为是滑动加载,需要添加scroll事件去监听然后执行相应回调 上拉加载主要计算触摸滚动距离,滑动加载主要计算containe

  • 深入解析Vue源码实例挂载与编译流程实现思路详解

    在正文开始之前,先了解vue基于源码构建的两个版本,一个是 runtime only ,另一个是 runtime加compiler 的版本,两个版本的主要区别在于后者的源码包括了一个编译器. 什么是编译器,百度百科上面的解释是 简单讲,编译器就是将"一种语言(通常为高级语言)"翻译为"另一种语言(通常为低级语言)"的程序.一个现代编译器的主要工作流程:源代码 (source code) → 预处理器 (preprocessor) → 编译器 (compiler) →

  • 浅析vue 函数配置项watch及函数 $watch 源码分享

    Vue双向榜单的原理 大家都知道Vue采用的是MVVM的设计模式,采用数据驱动实现双向绑定,不明白双向绑定原理的需要先补充双向绑定的知识,在watch的处理中将运用到Vue的双向榜单原理,所以再次回顾一下: Vue的数据通过Object.defineProperty设置对象的get和set实现对象属性的获取,vue的data下的数据对应唯一 一个dep对象,dep对象会存储改属性对应的watcher,在获取数据(get)的时候为相关属性添加具有对应处理函数的watcher,在设置属性的时候,触发

  • Vue的data、computed、watch源码浅谈

    导读 记得初学Vue源码的时候,在defineReactive.Observer.Dep.Watcher等等内部设计源码之间跳来跳去,发现再也绕不出来了.Vue发展了很久,很多fix和feature的增加让内部源码越来越庞大,太多的边界情况和优化设计掩盖了原本精简的代码设计,让新手阅读源码变得越来越困难,但是面试的时候,Vue的响应式原理几乎成了Vue技术栈的公司面试中高级前端必问的点之一. 这篇文章通过自己实现一个响应式系统,尽量还原和Vue内部源码同样结构,但是剔除掉和渲染.优化等等相关的代

  • JDK动态代理步骤详解(源码分析)

    动态代理步骤 1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法 2.创建被代理的类以及接口 3.通过Proxy的静态方法 通过Proxy的静态方法 ProxyObject proxyObject = new ProxyObject(); InvocationHandler invocationHandler = new DynamicProxy(proxyObject); ClassLoader classLoader = proxyObject.getCl

随机推荐