美文网首页
模拟Vue双向数据绑定

模拟Vue双向数据绑定

作者: 眸晓 | 来源:发表于2020-07-21 15:41 被阅读0次

html部分:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>模拟vue双向绑定</title>
</head>
<body>
  <div id="root">
    <ul>
      <li>123</li>
      <li>456</li>
      <li>789</li>
    </ul>
    <p>{{nickname}}</p>
    <p>{{age}}</p>
  </div>
</body>
</html>

js部分:

class MyVue{
    static sign = /\{\{(.+?)\}\}/g;     //  {{ }}正则匹配
    constructor(options){
      const _this = this;
      // _ 标识内部属性  , $表示 只读私有属性
      this._el = options.el;
      this._data = options.data;

      // 监听数据的变化
      for(let i in this._data){
        let d = _this[i] = this._data[i] //将this._data的数据绑定到MyVue实例中
        Object.defineProperty(_this,i,{
          get(){
            return d
          },
          set(newValue){
            console.log(newValue)
            d = newValue;
            _this.render()
          }
        })
      }
      this._templateDOM = document.getElementById(this._el)
      this._parent = this._templateDOM.parentNode;
      this.render()
      options.mounted.bind(_this)()
    }
    // 渲染
    render(){
      // 1.获取每个dom及其子节点,正则匹配到每个节点
      let copyTemplate = this._templateDOM.cloneNode(true);   //深拷贝dom,含子节点
      this.compile(copyTemplate)
      this.update(copyTemplate)
    }

    // 编译
    compile( template ){
      let _this = this;
      let childNodes = template.childNodes;
      for(let i = 0;i<childNodes.length;i++){
        let type = childNodes[i].nodeType;
        if(type === 3){
          // 文本节点
          let txt = childNodes[i].nodeValue;
          txt = txt.replace(MyVue.sign,function(_,group){
            //js中的replace函数 是支持回调函数的,回调中的第一个参数是匹配到的参数,return可以返回一个希望匹配替换成的值
            let key = group.trim()
            let value = _this[key]
            return value;
          })
          childNodes[i].nodeValue = txt;
        }else if(type === 1){
          // node节点 递归调用
          _this.compile(childNodes[i])
        }
      }
    }
    // 更新替换
    update(realDom){
      let replacdChild = document.getElementById(this._el);
      this._parent.replaceChild(realDom,replacdChild)
    }
  }

  let VueDom = new MyVue({
    el:'root',
    data:{
      nickname:'我的名字',
      age:20
    },
    mounted(){
      setTimeout(() => {
        console.log('mounted',this)
        this.nickname = '你的你的'
      }, 2000);
    }
  })
  console.log(VueDom)

相关文章

网友评论

      本文标题:模拟Vue双向数据绑定

      本文链接:https://www.haomeiwen.com/subject/adwikktx.html