vue源码分析

115 阅读1分钟

1. vue简介

Vue.js是一款MVVM框架,上手快速简单易用,通过响应式在修改数据的时候更新视图。Vue.js的响应式原理依赖于Object.defineProperty

2. vue响应式原理

代码简单实现

将数据变成可观察的
const observable= (that, data) => {
    Object.keys(data).forEach(key => {
        Object.defineProperty(that, key, {
            enumerable: true,
            configurable: true,
            get (){
                return that._data[key];
            },
            set (newVlaue){
                that._data[key] = newVlaue;
                that.render(that._data[key]);
            }
        })
    })
}

定义Vue类
lass Vue {
  constructor(options) {
      this._data = options.data;
      this.render = options.render;
      this._proxy.call(this, options.data);
  }
  // 实现data数据代理
  _proxy(data) {
      const that = this;
      observable(that, data);
  }
}
写好了来测试下吧
// vue的调用
const app = new Vue({
    data: {
        number: 0
    },
    render (value){
        console.log(value);
    }
})
// 测试响应式
setTimeout(()=>{
    app.number = 7;
}, 3000)
代理解释

需要对app._data.text操作才会触发set。为了偷懒,我们需要一种方便的方法通过app.text直接设置就能触发set对视图进行重绘。那么就需要用到代理。代码使用call来实现;

3. vue依赖收集

Dep

用于依赖收集收集的类,在每次get时候进行收集,computed,watch同时也会收集

class Dep{
    constructor(){
        this.subs = [];
    }
    add(sub){
        this.subs.push(sub);
    }
    remove(sub){
        remove(this.subs, sub);
    }
    notify(key,value){
        const subs = this.subs.slice();
        subs.forEach(item=>{
            item.update(key,value);
        })
    }
}
// remove
const remove = (arr, sub)=>{
    if(!arr.length) return arr;
    const index = arr.indexOf(sub);
    if(index>-1){
        arr.splice(index, 1);
    }
    return arr;
}

watcher

在修改data中数据的时候会触发dep对象的notify,通知所有Watcher对象去修改对应视图。

class Watcher{
    constructor(vm, callback){
        this.callback = callback;
        this.vm = vm;
        Dep.target = this;
        this.callback.call(this.vm);
    }
    update(key, value){
        this.callback.call(this.vm);
    }
}

定义vue,依赖收集

const observer = (data, render)=>{
    Object.keys(data).forEach(key => {
        const dep = new Dep();
        Object.defineProperty(data, key, {
            enumerable: true,
            configurable: true,
            get(value){
                if(Dep.target){
                    dep.add(Dep.target);
                }
                return value;
            },
            set(value){
                console.log(value, dep);
                dep.notify(key,value);
            }
        })
    })
}
class Vue {
    constructor(options){
        this._data = options.data;
        observer(this._data, options.render);
        let watcher = new Watcher(this,options.render);
    }
}

最后

有什么问题希望指出,欢迎大神指点,vue的其他相关知识会继续更新;