手写Vue2.0 数据劫持的示例
一:搭建webpack
简单的搭建一下webpack的配置。新建一个文件夹,然后init一下。之后新建一个webpack.config.js文件,这是webpack的配置文件。安装一下简单的依赖。
npminstallwebpackwebpack-cliwebpack-dev-server-D
在同级目录下新建一个public/index.html和src/index.js,作为出口文件和入口文件。
j简单配置一下webpack,在webpack.config.js文件中:
constpath=require('path'); constHtmlWebpackPlugin=require('html-webpack-plugin'); module.exports={ entry:'./src/index.js', output:{ filename:'bundle.js', path:path.resolve(__dirname,'dist') }, resolve:{ modules:[ path.resolve(__dirname,''),path.resolve(__dirname,'node_modules') ] }, plugins:[ newHtmlWebpackPlugin({ template:path.resolve(__dirname,'public/index.html') }) ] }
ok,基本配置好webpack就可以开始正题了。
二:数据劫持
在v2中,通过newVue(el,options)的方式,完成vue的实例化。我们需要新建一下vue文件,把数据劫持的方法统一到vue中。
新建一个vue/index.js,作为数据劫持的入口文件。
import{initState}from'./init.js'; functionVue(options){ this._init(options);//数据初始化 } Vue.prototype._init=function(options){ varvm=options;//保存一下实例 vm.$options=options;//实例挂载 initState(vm);//实例初始化 }
新建一个init.js文件初始化实例:
初始化的时候注意几个问题:
1. 需要分别对computed,watch,data进行处理。
2.不要在用户定义的data上直接修改。
3.官方指定data为函数,是为了保证组件内部有自己的作用域不会有污染,直接访问data函数是不行的,需要自动执行。data也可以是对象(需要考虑到这个情况)
4.这种方式获取data是通过vm._data.xxx但是在vue中不需要data来获取,所以这里需要拦截重写。
5.内部的引用类型需要递归
functioninitState(vm){ varoptions=vm.$options;//获取options if(options.data){ initData(vm);//因为computed,watch都需要在这里初始化,所以针对data初始化 }; functioninitData(vm){ vardata=vm.$options.data;//对data重新赋值,不要改变用户定义的data data=vm._data=typeofdata==='function'?data.call(vm):data||{}; for(varkeyindata){ proxyData(vm,'_data',key);//对data的取值重新赋值 }; observe(vm._data);//对data内部进行观察 }
新建一个proxy.js作为代理层:
functionproxyData(vm,target,key){ Object.defineProperty(vm,key,{ get(){ //这里做了拦截:vm.xxx=>vm._data.xxx returnvm[target][key]; }, set(newValue){ //vm.xxx=yyy===>vm._data.title=yyy vm[target][key]=newValue; } }) } exportdefaultproxyData;
处理好了访问问题,现在需要递归一下data内部元素。obseve(vm._data);
新建一个observe.js:
functionobserve(data){ if(typeofdata!=='object'||data=null)return; returnnewObserver(data);//如果是应用类型,直接添加一个观察者 }
新建一个观察者:observer.js
functionObserver(data){ if(Array.isArray(data)){ //处理数组 data._proto_=arrMethods; } else{ //处理对象 this.walks(data); } } Observer.prototype.walks=function(data){ letkeys=Object.keys(data);//拿到data下面所有的key,并且还是一个数组 for(vari=0;i新建一个reactive.js 处理对象等响应式
functiondefineReactiveData(data,key,value){ observe(value);//对子元素接着递归。 Object.defineProperty(data,key,{ get(){ returnvalue; }, set(newValue){ if(newValue===value)return; value=newValue;//触发更改 } } ) };ok,这里处理好了对象的数据劫持,剩余的需要处理数组了
在V2中采用重写原型上的7种方法,做到数据劫持。
劫持数组:
新建一个Array.js文件:
import{ARR_METHODS}from'./config.js'; //7个数组方法的合集 importobserveArrfrom'./observeArr.js'; varoriginArrMethods=Array.prototype, arrMethods=Object.create(originArrMethods); ARR_METHODS.map(function(m){ arrMethods[m]=function(){ varargs=Array.prototype.slice.call(arguments);//类数组转为数组 varrt=originArrMethods[m].apply(this,args); varnewArr; switch(m){ case'push': case'ushift': newArr=args; case'splice': newArr=args.slice(2); break; default: break;}; newArr&&observeArr(newArr); returnrt; } }); export{arrMethods}observeArr(newArr):数组也可能有嵌套,所以需要对数据进行观察。
importobservefrom"./observe"; functionobserveArr(arr){ for(vari=0;i三:总结
基本流程就是这样的,不仅仅是object.defineProperty对数据进行get和set这么简单。总结一下主要流程:
(1):在初始化的时候:保存一下实例,挂载实例。通过initState方法来初始化数据,这里主要是data数据,也有computed和watch需要处理。
(2):调用initData();重新赋值data,然后执行data,修改用户获取data属性的写法统一为this.xxx同时observe(data)
(3):在observe(data)的时候需要对data进行判断,如果是引用类型需要加上一个观察者observer,同时在观察者终判断data是为数组还是对象,对象直接重新触发object.defineProperty,同时对内部重新observe。如果是数组直接重新7种数组方法,然后对数组内部接着observe。
以上就是手写Vue2.0数据劫持的示例的详细内容,更多关于手写vue数据劫持的资料请关注毛票票其它相关文章!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。