学习vue实现简单的初始化以及数据双向绑定

学习https://juejin.im/entry/583bd53ca22b9d006dce11d7讲解的vue双向绑定实现原理

html

<div id="app">
        <input class="input" v-model="text" type="text" value="">
        {{text}}
        <p>{{text}}</p>
</div>
<script src="./vue双向数据绑定原理.js"></script>

js

// 定义vue类
function _vue(options) { 
    this.data = options.data;
    let data = this.data;
    observe(data, this);
    let id = options.el;
    let dom = nodeToFragment(document.getElementById(id), this);
    document.getElementById(id).appendChild(dom);
}
// 处理子节点并放入documentFragment
function nodeToFragment(node, vm) {
    let fragment = document.createDocumentFragment();
    let child;
    while(child = node.firstChild){
        compile(child, vm);
        fragment.appendChild(child);
    }
    return fragment;
}
// 节点分类处理,初始化节点内数据,绑定view => model
function compile(node, vm) { 
    let reg = /\{\{(.*)\}\}/;
    // 元素节点
    if(node.nodeType === 1) {
        let attr = node.attributes;
        for (let attrItem of attr) {
            if (attrItem.nodeName === 'v-model') {
                let name = attrItem.nodeValue;
                node.addEventListener('keyup', (e)=>{
                    vm[name] = e.currentTarget.value;
                })
                node.value = vm[name];
                node.removeAttribute('v-model');
            }
        }
        for (let item of node.childNodes) {
            compile(item, vm);
        }
    }
	// 文本节点
    if(node.nodeType === 3) {
        if(reg.test(node.nodeValue)) {
            let name = RegExp.$1;
            name = name.trim();
            // node.nodeValue = vm[name];
            new Watcher(vm, node, name);
        }
    }
}
// 设置访问器属性
function defineReactive(obj, key, val) { 
    let dep = new Dep();
    Object.defineProperty(obj, key, {
        get: function (param) { 
            if (Dep.target) dep.addSub(Dep.target);
            return val;
         },
        set: function (newVal) { 
            if (newVal === val) return;
            val = newVal;
            dep.notify();
         }
    })
    if (val instanceof Object){
        observe(val, obj)
    }
 }

function observe(obj, vm) { 
    Object.keys(obj).forEach(function (key) { 
        defineReactive(vm, key, obj[key]);
     })
 }
// 订阅者列表
function Dep() {
    this.subs = [];
}
Dep.prototype.notify = function () { 
    this.subs.forEach(function (subs) { 
        subs.update();
     })
 }
Dep.prototype.addSub = function (watcher) { 
    this.subs.push(watcher)
 }
// 订阅者类
function Watcher(vm, node, name) {
    Dep.target = this;
    this.name = name;
    this.node = node;
    this.vm = vm;
    this.update();
    Dep.target = null;
}
Watcher.prototype = {
    update: function (){
        this.get();
        this.node.nodeValue = this.value;
    },
    get: function (){
        this.value = this.vm[this.name];
    }
}


let vm = new _vue({
    el: 'app',
    data: {
        text: 'hello world!'
    }
})

你可能感兴趣的:(前端知识仓库,面试题,javascript,vue.js)