vue简单实现

HTML模板

一:


二:

三:


4:


class Compiler {

constructor(el, vm) {

this.el =this.isElementNode(el) ? el : document.querySelector(el);

    this.vm = vm;

    const fragment =this.compileFragment(this.el);

    this.compile(fragment);

    this.el.appendChild(fragment);

  }

compile(fragment) {

const childNodes = Array.from(fragment.childNodes);

    childNodes.forEach(childNode => {

if (this.isElementNode(childNode)) {

// 标签节点 h1 / input,读取属性,查看是否有 v- 开头的内容

        this.compileElement(childNode);

      }else if (this.isTextNode(childNode)) {

// 内容文本节点 {{ msg }} 是否有双括号语法

        this.compileText(childNode);

      }

if (childNode.childNodes && childNode.childNodes.length) {

this.compile(childNode);

      }

});

  }

compileElement(node) {

// v-model v-text v-on:click

    const attributes = Array.from(node.attributes);

    attributes.forEach(attr => {

const { name, value } = attr;

      if (this.isDirector(name)) {

// 指令v-model, v-text, v-bind, v-on:click

        const [, directive] = name.split('-');

        const [compileKey, eventName] = directive.split(':');

        utils[compileKey](node, value, this.vm, eventName);

      }else if (this.isEventName(name)) {

// @ 方法执行

        const [, eventName] = name.split('@');

        utils['on'](node, value, this.vm, eventName);

      }

})

}

isDirector(name) {

return name.startsWith('v-');

  }

isEventName(name) {

return name.startsWith('@');

  }

compileText(node) {

// {{ msg }}

    const content = node.textContent;

    if (/\{\{(.+)\}\}/.test(content)) {

utils['text'](node, content, this.vm);

    }

}

compileFragment(el) {

const f = document.createDocumentFragment();

    let firstChild;

    while(firstChild = el.firstChild) {

f.appendChild(firstChild);

    }

return f;

  }

isTextNode(el) {

return el.nodeType ===3;

  }

isElementNode(el) {

return el.nodeType ===1;

  }

}

五:


六:


let TARGET =null;

const utils = {

getValue(expr, vm) {

return vm.$data[expr.trim()];

  },

  setValue(expr, vm, newValue) {

vm.$data[expr] = newValue;

  },

  model(node, value, vm) {

const initValue =this.getValue(value, vm);

    new Watcher(value, vm, (newValue) => {

this.modelUpdater(node, newValue);

    });

    node.addEventListener('input', (e) => {

const newValue = e.target.value;

      this.setValue(value, vm, newValue);

    });

    this.modelUpdater(node, initValue);

  },

  text(node, value, vm) {

let result;

    if (value.includes('{{')) {

// {{ xxx }}

      result = value.replace(/\{\{(.+?)\}\}/g, (...args) => {

const expr = args[1];

        new Watcher(expr, vm, (newVal) => {

this.textUpdater(node, newVal);

        })

return this.getValue(args[1], vm);

      });

    }else {

// v-text="xxx"

      result =this.getValue(value, vm);

    }

this.textUpdater(node, result);

  },

  on(node, value, vm, eventName) {

const fn = vm.$options.methods[value];

    node.addEventListener(eventName, fn.bind(vm), false);

  },

  textUpdater(node, value) {

node.textContent = value;

  },

  modelUpdater(node, value) {

node.value = value;

  }

}

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容