- 我们的vue.js文件编译工作配置好之后,就可以继续写了,首先在html中调用vue,声明好数据,然后一步一步的完善vue中的功能
- 引入vue.js
-
<script src="./dist/vue.js"></script>
-
声明好数据
-
<div id="app">{{name}}</div> <script> let vm = new Vue({ el:'#app', data:{ name:'zf' } }) </script>
-
-
- 完善vue
- 可以看到,声明数据中,是通过新建一个类进行声明,类中包含了两个属性,一个确定要绑定的元素,一个是数据,因此在vuejs中可以更改为:
- 创建一个构造函数
-
function Vue(options) { //options 为传入的选项 this._init(options) } export default Vue;
options为用户传进来的参数,_init用来初始化数据
-
现在开始完善初始化函数
-
新建一个init.js文件
-
声明初始化函数,并将_init函数定义在vue原型上
-
在原型上新添加一个属性用来保存数据($options)
-
调用初始化状态函数,对每种数据进行初始化
-
import { initState } from "./state"; export function initMixin(Vue){ // 在Vue类的原型上添加这个函数 Vue.prototype._init = function(options){ const vm = this; // 在原型上添加一个属性保存数据 vm.$options = options;// //开始对数据进行劫持 initState(vm); } }
-
初始化数据函数为initData,主要作用
-
判断其是对象类型还是数组类型,并获取对象类型数据
-
新建观察者类型,对对象数据进行观察
-
import { observe } from "./observer/index"; import { isFunction } from "./utils"; export function initState(vm){ const opts = vm.$options; if(opts.data){ // 数据存在,则劫持数据 initData(vm); } } function initData(vm){ let data = vm.$options.data; // 判断data是函数还是对象,获取其对象数据 data = vm._data = isFunction(data)?data(vm):data; console.log(vm._data) //观察数据 observe(data); }
-
观察者类新建如下:
-
新建walk函数遍历对象数据的key 和value
-
调用defineReactive函数对对象属性进行劫持
-
第一步便利的value可能也是对象类型,所以要在这个函数开头再次调用观测者类,监测这个value
-
set函数只是将新值复制给旧值,如果新值是对象类型,则无法劫持,所以需要在这里再次调用观测者类
-
import { isObject } from "../utils"; // 创建观测者 class Observer{ constructor(data){ //对对象中的所有属性进行劫持 this.walk(data); } walk(data){ Object.keys(data).forEach(key =>{ defineReactive(data,key,data[key]); }) } } function defineReactive(data,key,value){ observe(value) Object.defineProperty(data,key,{ get(){ return value; }, set(newV) { observe(value) value = newV; } }) } export function observe(data) { // 判断数据是否为对象 if(!isObject(data)){ return ; } //创建观测者来观测数据 return new Observer(data); }
-
-
-
-
-
- 可以看到,声明数据中,是通过新建一个类进行声明,类中包含了两个属性,一个确定要绑定的元素,一个是数据,因此在vuejs中可以更改为:
- 解决代理问题
- 根据上述,我们可以通过vm._data.name来访问name属性,但是习惯上,vue直接通过vm.name来访问,因此我们需要在进行数据劫持,将数据放在vue上
- 要想完成这个逻辑,和之前的劫持一样,只需要在vm上面劫持一下数据
-
function proxy(vm,source,key){ Object.defineProperty(vm,key,{ get(){ return vm[source][key]; }, set(newV){ vm[source][key] = newV; } }) } function initData(vm){ let data = vm.$options.data; // 判断data是函数还是对象,获取其对象数据 data = vm._data = isFunction(data)?data(vm):data; for( let key in data){ proxy(vm,'_data',key); } //观察数据 observe(data); }
- 根据上述,我们可以通过vm._data.name来访问name属性,但是习惯上,vue直接通过vm.name来访问,因此我们需要在进行数据劫持,将数据放在vue上
- 引入vue.js
手撕Vue源码(二)对象数据劫持
最新推荐文章于 2023-03-14 16:47:56 发布
![](https://img-home.csdnimg.cn/images/20240711042549.png)