赞
踩
前言:什么是vue响应式?官网解释:Vue 最独特的特性之一,是其非侵入性的响应式系统。数据模型仅仅是普通的 JavaScript 对象。而当你修改它们时,视图会进行更新。
简而言之就是数据变页面变
实现原理:
Vue在组件和实例初始化的时候,会将data里的数据进行数据劫持(object.definepropty对数据做处理)。被解除过后的数据会有两个属性:一个叫getter,一个叫setter。
getter是使用数据的时候触发,setter是在修改数据的时候触发,修改数据的时候触发setter,同时也触发了底层的watcher监听,通知dom修改刷新(vue2.0)
Vue3.0是使用proxy()来实现对数据处理
1.导出vue构造函数
import {initMixin} from './init';
function Vue(options) {
this._init(options);
}
initMixin(Vue); // 给原型上新增_init方法
export default Vue;
2.init方法中初始化vue状态
import {initState} from './state';
export function initMixin(Vue){
Vue.prototype._init = function (options) {
const vm = this;
vm.$options = options
// 初始化状态
initState(vm)
}
}
根据不同属性进行初始化操作
export function initState(vm){ const opts = vm.$options; // 判断里面有哪些数据,并进行初始化 // 如 props, data, methods, computed, watch... if(opts.porps){ initProps(vm); } if(opts.methods){ initMethod(vm); } if(opts.data){ // 初始化data initData(vm); } if(opts.computed){ initComputed(vm); } if(opts.watch){ initWatch(vm); } } function initProps(){} function initMethod(){} function initData(vm){ // 这就就写data中的数据了 // 数据响应式原理 let data = vm.$options.data; // 用户传入的数据 // vm._data 就是检测后的数据了 data = vm._data = typeof data === 'function' ? data.call(vm) : data; // 观测数据 observe(data); // 观测这个数据 } function initComputed(){} function initWatch(){}
3.初始化数据
import {observe} from './observer/index.js'
function initData(vm){ //用户传递过来data中的数据
let data = vm.$options.data; //vm._data 就是监测后的数据
data = vm._data = typeof data === 'function' ? data.call(vm) : data;
// 观测数据
observe(data);
}
递归属性劫持
class Observer { // 观测值 constructor(value){ this.walk(value); } walk(data){ // 让对象上的所有属性依次进行观测 let keys = Object.keys(data); for(let i = 0; i < keys.length; i++){ let key = keys[i]; let value = data[key]; defineReactive(data,key,value); } } } function defineReactive(data,key,value){ observe(value); // 判断是否是对象 Object.defineProperty(data,key,{ // 添加get set方法 get(){ return value }, set(newValue){ if(newValue == value) return; observe(newValue); value = newValue } }) } export function observe(data) { // 判断data是不是对象,当null为空是也是返回object if(typeof data !== 'object' && data != null){ return; } return new Observer(data); }
上面通过打印可以查看到data中的属性都添加了get和set属性(对象属性)
import {arrayMethods} from './array'; class Observer { // 观测值 constructor(value){ // 对数组索引进行拦截 性能差而且直接更改索引的方式并不多 Object.defineProperty(data,'__ob__',{ // __ob__ 是一个响应式饿表示 对象数组都有 enumerable:false, // 不可枚举 configurable:false, value:this }) // data.__ob__ = this; // 相当于在数据上可以获取到__ob__这个属性 指代的是Observer的实例 if(Array.isArray(data)){ // vue如何对数组进行处理呢? 数组用的是重写数组的方法 函数劫持 // 改变数组本身的方法我就可以监控到了 data.__proto__ = arrayMethods; // 通过原型链 向上查找的方式 // [{a:1}] => arr[0].a = 100 this.observeArray(data); }else{ this.walk(data); // 可以对数据一步一步的处理 } } observeArray(value){ for(let i = 0 ; i < value.length ;i ++){ observe(value[i]); } } }
重写数组原型方法
let oldArrayProtoMethods = Array.prototype; export let arrayMethods = Object.create(oldArrayProtoMethods); let methods = [ // 这七种方法会改变数组 'push', 'pop', 'shift', 'unshift', 'reverse', 'sort', 'splice' ]; methods.forEach(method => { arrayMethods[method] = function (...args) { const result = oldArrayProtoMethods[method].apply(this, args); const ob = this.__ob__; let inserted; switch (method) { case 'push': case 'unshift': inserted = args; break; case 'splice': inserted = args.slice(2) default: break; } if (inserted) ob.observeArray(inserted); // 对新增的每一项进行观测 return result } })
增加__obo__属性
class Observer {
constructor(value){
Object.defineProperty(value,'__ob__',{
enumerable:false,
configurable:false,
value:this
});
// ...
}
}
给所有响应式数据增加标识,并且可以在响应式上获取Observer实例上的方法;
最后附上代码:码云link;
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。