vue的简单实现

北城余情 提交于 2020-01-27 22:14:40

因为vue主要是通过数据劫持来实现的,通过getset来完成数据的读取和更新

这里简单实现data,v-model,computed

1模版

    <!DOCTYPE html>
    <html>
    <head>
        <title></title>
    </head>
    <body>
    <div id="app">
        <div>{{a.a}}</div>
        <div>{{c}}</div>
        <input type="text" v-model="c">
        {{hello}}
    </div>
    <script src="./mvvm.js"></script>
    <script type="text/javascript">
    
    let vue = new Vue2({
        el:"#app",
        data:{
            a:{a:1},
            b:[1,2,3],
            c:123123
        },
        computed:{
            hello(){
                return this.a.a+this.c;
            }
        }
    })
    </script>
    </body>
    </html>

js

function Vue2(options = {}) {
    this.$options = options;
    let data = this._data = this.$options.data;
    observe(data);
    // this代理了this._data
    for (let key in data) {
        Object.defineProperty(this, key, {
            enumerable: true,
            get() {
                return this._data[key];
            },
            set(newVal) {
                this._data[key] = newVal
            }
        })
    }
    initComputed.call(this);//初始化computed
    new Compile(options.el, this)
}
//计算属性的实现
function initComputed(){
    let vm = this;
    let computed = this.$options.computed;
    Object.keys(computed).forEach(function (k) {
        Object.defineProperty(vm,k,{        //如果给的是函数那么调取函数,如果是对象那么获取对象的get方法
            get:typeof computed[k] === 'function'?computed[k]:computed[k].get(),
            set(){}
        })
    })
}

function Compile(el, vm) {
    // el表示替换的范围
    vm.$el = document.querySelector(el);
    let frament = document.createDocumentFragment();//文案碎片
    while (child = vm.$el.firstChild) {//将app中的内容,移入到内存中
        frament.appendChild(child)
    }
    //查找节点中的{{}}
    replace(frament);

    function replace(frament) {
        Array.from(frament.childNodes).forEach(function (node) {
            let text = node.textContent;
            let reg = /\{\{(.*)\}\}/;
            //判断{{}}
            if (node.nodeType === 3 && reg.test(text)) {
                console.log(RegExp.$1)//取出花括号中的变量
                let arr = RegExp.$1.split('.');//[a,a],[b],[c]
                let val = vm;
                arr.forEach(function (k) {
                    val = val[k]
                })
                new Watcher(vm,RegExp.$1,function (newVal) {
                    node.textContent = text.replace(/\{\{(.*)\}\}/, newVal)
                })
                //
                node.textContent = text.replace(/\{\{(.*)\}\}/, val)
            }
            //判断v-model
            if(node.nodeType ===1 /*元素节点*/ ){
                let nodeAttrs = node.attributes;//获取属性
                console.log(nodeAttrs)
                Array.from(nodeAttrs).forEach(function (attr) {
                    console.log(attr)
                    let name = attr.name;
                    let exp = attr.value;
                    if(name.indexOf('v-')==0){
                        node.value = vm[exp];
                    }
                    new Watcher(vm,exp,function (newVal) {
                        node.value = newVal;
                    });
                    node.addEventListener('input',function (e) {
                        let newVal = e.target.value;
                        vm[exp] = newVal;
                    })
                })
            }
            if (node.childNodes) {
                replace(node)
            }
        });
    }
    vm.$el.appendChild(frament)
}

//观察者 给队形增加Object.defineProperty
// 数据劫持
function Observe(data) {
    let dep = new Dep();
    for (let key in data) {
        let val = data[key];
        observe(val);
        Object.defineProperty(data, key, {
            enumerable: true,
            get() {
                Dep.target&&dep.addSub(Dep.target);//监控值的变化
                return val
            },
            set(newVal) {
                if (newVal === val) {
                    return
                }
                val = newVal;
                observe(newVal)
                dep.notify()//让所有的watch的update方法执行
            }
        })
    }
}

function observe(data) {
    if (typeof data !== "object") return;
    return Observe(data)
}

//发布订阅
function Dep() {
    this.subs = []
}
Dep.prototype.addSub = function (sub) {//订阅
    this.subs.push(sub)
}
Dep.prototype.notify = function () {
    this.subs.forEach(sub=>sub.update())
}
function Watcher(vm,exp,fn) {
    this.vm = vm;
    this.exp = exp;
    this.fn = fn;
    Dep.target = this;
    let val = vm;
    let arr = exp.split('.')
    arr.forEach(function (k) {
        val = val[k]
    })
    Dep.target = null;
}
Watcher.prototype.update=function () {
    let val = this.vm;
    let arr = this.exp.split('.');
    arr.forEach(function (k) {
        val = val[k]
    })
    this.fn(val)
}

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!