1.工欲善其事,必先利其器。首先搭建我们的开发环境,先使用npminit-y创建一个初始配置文件,然后下载我们后面需要的开发依赖:npmiwebpackwebpack-cliwebpack-dev-serverhtml-webpack-plugin--save-devcreatenewwebpack.config.js用于编写webpack配置,新建src/index.js作为项目入口文件,然后新建public/index.html作为模板文件。webpack的基本配置如下:constpath=require('path');consthtmlWebpackPlugin=require('html-webpack-plugin');module.exports={entry:'./src/index.js',//将我们src的index.js打包为entryoutput:{filename:'bundle.js',path:path.resolve(__dirname,'dist')},devtool:'source-map',resolve:{//默认让import去我们的source文件夹找模块,然后去node_modules找模块:[path.resolve(__dirname,'source'),path.resolve('node_modules')]},plugins:[newhtmlWebpackPlugin({template:path.resolve(__dirname,'public/index.html')})]}使用npm脚本启动我们的项目,以及将package.json中的脚本修改为:"scripts":{"start":"webpack-dev-server","build":"webpack"}然后执行npmstart来启动我们的项目。2、创建我们的基础框架,修改我们上面默认的导入文件路径。这时候我们在source文件夹下新建一个vue/index.js,然后在我们的src/index.js中importimportVuefrom'vue';//默认会搜索源码目录下的vue文件夹。此时source/vue/index.js中的js就可以正常执行了。让我们继续编写我们的src/index.js。之前写的Vue我们已经介绍过了,接下来我们就模拟Vue的语法来写:importVuefrom'vue';//默认会在源目录下搜索vue文件夹letvm=newVue({el:'#app',//表示要渲染的元素是#appdata(){return{msg:'hello',school:{name:'black',age:18},arr:[1,2,3],}},computed:{},watch:{}});然后我们要编写实现我们的Vue代码,vue/index.js:import{initState}from'./observe';functionVue(options){//Vue中原始用户传入的数据this._init(选项);//初始化Vue并传入用户选项}Vue.prototype._init=function(options){//vue中初始化this.$options是指Vue中的参数letvm=this;vm.$options=选项;//MVVM原理,需要重新初始化数据initState(vm);}exportdefaultVue;//默认先导出对于一个Vue,我们首先要初始化Vue,初始化用户传入的数据,新建一个observe/index.js来实现对用户传入数据的初始化:export函数initState(vm){让opts=vm.$options;如果(opts.data){initData(vm);//初始化数据}if(opts.computed){initComputed();//初始化计算属性}if(opts.watch){initWatch();//初始化手表}}/***初始化数据*将使用用户传入的数据通过Object.defineProperty重新定义*/functioninitData(vm){}/***初始化计算属性*/functioninitComputed(){}/***初始化watch*/functioninitWatch(){}3。数据初始化首先我们要实现用户传入的数据的初始化,也就是常说的使用Object.defineProperty进行数据劫持,重写getter和setter,下面实现initData的具体内容:/***将对vm的取值和赋值操作代理到vm._data属性*代理数据实现例如:vm.msg=vm._data.msg*/functionproxy(vm,source,key){Object.defineProperty(vm,key,{get(){returnvm[source][key];},set(newValue){vm[source][key]=newValue;}})}/***初始化数据*通过用户通过Object传入的数据.defineProperty重新定义*/functioninitData(vm){letdata=vm.$options.data;//用户传入的数据data=vm._data=typeofdata==='function'?data.call(vm):数据||{};for(让我们输入数据){proxy(vm,'_data',key);//将对vm的取值和赋值操作代理到vm._data属性上,方便我们直接使用vm值}observe(vm._data);//观察数据}exportfunctionobserve(data){if(typeofdata!=='object'||data==null){return;//不是对象或null不执行后续逻辑}returnnewObserver(data);}4.数据劫持核心方法实现我们到这个目录下新建一个observer.js来实现我们的Observer:import{observe}from'./index';/***定义响应式数据变化*@param{Object}data用户传入的数据*@param{string}key数据的key*@param{*}value数据对应的key的值*/exportfunctiondefineReactive(data,key,value){观察(值);//如果value还是一个对象,需要劫持Object.defineProperty(data,key,{get(){console.log('getdata');returnvalue;},set(newValue){console.log('setdata');if(newValue===value)return;value=newValue;}});}classObserver{constructor(data){//data===vm._data//为用户使用Object.definePropertydata重新定义this.walk(data);}/***循环数据遍历*/walk(data){letkeys=Object.keys(data);for(leti=0;i
