数据响应式 模仿vue 渲染数据、双向绑定

模仿vue 渲染数据、双向绑定

创建html页面

  <div id="app">
    {{ name }}
    <div>{{age}}</div>
    <span>{{message}}</span>
    <div>
    <input v-model="model" />
    {{ model }}
  </div>

js 部分

class Vue extends EventTarget {
  constructor(option) {
    super();
    this.option = option;
    // 赋值data值
    this.$data = this.option.data;
    // 获取当前 app
    this.el = document.querySelector(this.option.el);
    this.observe(this.$data)
    this.compilNode(this.el)
  }

  observe(data) {
    const that = this;
    this.$data = new Proxy(data, {
      get(target, prop) {
        // 返回调用值
        return target[prop];
      },
      set(target, prop, newValue) {
        // 创建一个事件对象,名字为newEvent,类型为 prop传递名称
        let event = new CustomEvent(prop, {
          detail: newValue
        })
        // 触发自定义事件 
        that.dispatchEvent(event);
        // target[prop] = newValue
        // return newValue
        return Reflect.set(target, prop, newValue)
      }
    })
  }

  compilNode(el) {
    let child = el.childNodes;
    Array.from(child).forEach((node) => {
      if(node.nodeType === 3) {
        let text = node.textContent;
        let reg = /{{s*([^s{}]+)s*}}/g; //匹配当前页面{{name}}值
        if(reg.test(text)){
          let $1 = RegExp.$1;
          // 查看当前data 是否有值 && 替换当前内容
          this.$data[$1] && (node.textContent = text.replace(reg, this.$data[$1]));
          // 将自定义事件绑定在 EventTarget 对象上
          this.addEventListener($1, e=>{
            // 监听当前 name名称 替换DOM内容
            node.textContent = text.replace(reg, e.detail);
          })
        }
      } else if(node.nodeType === 1){
        let attr = node.attributes;
        // 获取当前自定义属性 查看是否为v-model
        if(attr.hasOwnProperty('v-model')) {
          // 获取v-model 值
          let keyName = attr['v-model'].nodeValue;
          // 将仓库值赋值给当前文本框
          node.value = this.$data[keyName];
          // 监听文本框内容是否改变
          node.addEventListener('input', e => {
            // 修改仓库值
            this.$data[keyName] = node.value
          })
        }
        // 传递当前元素 处理元素标签
        this.compilNode(node);
      }
    })
  }
}
 // 引用
   var vm = new Vue({
    el: '#app',
    data: {
      name: '张三',
      age: 15,
      model: '这是双向数据绑定值',
      message: '这是一个说明文件'
    }
  })

视图

原文地址:https://www.cnblogs.com/wangyong1997/p/13259104.html