当前位置: 移动技术网 > IT编程>开发语言>JavaScript > vue 数据双向绑定 个人实现版

vue 数据双向绑定 个人实现版

2020年04月26日  | 移动技术网IT编程  | 我要评论
html <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title></title> </head> <body> <div id="app"><input type="text" v-model="text" /> {{text}} ...

html

<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <title></title>
  </head>

  <body>
    <div id="app"><input type="text" v-model="text" /> {{text}}</div>
  </body>
  <script src="./mvvm.js"></script>
  <script type="text/javascript">
    var vm = new vue({
      el: 'app',
      data: {
        text: '超哥哥',
      },
    })
    vm.data.text = '超哥哥to'
  </script>
</html>

js

class vue {
  constructor(options) {
    this.data = options.data //创建data 数据
    this.optionsto = options
    this.observe(this.data, this) //对数据数据进行双向绑定
    let id = options.el // 获取挂载点
    let dom = this.nodetoframent(document.getelementbyid(id), this) //创建文档碎片,并处理
    document.getelementbyid(id).appendchild(dom) //将处理好的文档碎片添加到 文档中
  }
  nodetoframent(node, vm) {
    let fragment = document.createdocumentfragment() //创建文档碎片
    let child
    while ((child = node.firstchild)) {
      // 这里是一个判断条件条件,当node.firstchild 为null 的时候会停下来
      this.compile(child, vm) //执行对 节点的处理
      fragment.appendchild(child) // 将 处理完的数据添加到 文档碎片容器中
    }
    return fragment
  }
  compile(node, vm) {
    let reg = /\{\{(.*)\}\}/ //创建去除双花括号的 正则
    if (node.nodetype === 1) {
      //如果 节点类型等于 1, 那么代表是 元素节点
      let attr = node.attributes //拿到 元素节点的所有属性
      for (let i = 0; i < attr.length; i++) {
        if (attr[i].nodename == 'v-model') {
          //如果 元素节点中出现 v-model 属性
          let name = attr[i].nodevalue //拿到 属性对应的 值
          node.addeventlistener('input', function (e) {
            vm.data[name] = e.target.value
          })
          new watcher(vm, node, name)
          //   node.value = vm.data[name] //去data 里面查找对应的 数据并赋值给对应 元素
          node.removeattribute('v-model')
        }
      }
    }
    if (node.nodetype === 3) {
      //如果是 文本节点
      if (reg.test(node.nodevalue)) {
        let name = regexp.$1 //调用正则
        name = name.trim() //去掉前后空格
        // node.nodevalue = vm.data[name] //去data 里面查找对应的 数据并赋值给对应 元素
        new watcher(vm, node, name) //实例化watcher 监听数据
      }
    }
  }
  observe(obj) {
    if (!obj || typeof obj !== 'object') {
      return
    } else {
      object.keys(obj).foreach((key) => {
        this.defnereactive(obj, key, obj[key])
      })
    }
  }
  defnereactive(obj, key, val) {
    let dep = new dep() //dep 函数相当于是一个中间件,桥梁
    this.observe(val)
    object.defineproperty(obj, key, {
      get() {
        if (dep.target) {
          dep.addsub(dep.target) //只要每次获取数据 都将全局变量里面的数据存储到dep 里面,以便设置数据时调用
        }
        return val
      },
      set(newval) {
        if (newval === val) {
          return
        } else {
          val = newval
          dep.notify() //触发notify 方法,dep 里面的数据呈现到页面
        }
      },
    })
  }
}
class dep {
  //dep 函数相当于是一个中间件,桥梁
  constructor() {
    this.subs = []
  }
  addsub(sub) {
    this.subs.push(sub)
  }
  notify() {
    this.subs.foreach((sub) => {
      sub.update()
    })
  }
}
class watcher {
  constructor(vm, node, name) {
    dep.target = this //dep.target 是一个全局变量,存储的是 this指向的 vue 函数里面的数据
    this.vm = vm
    this.node = node
    this.name = name
    this.update()
    dep.target = null //将 dep.target 变量清空,从而保证dep.target 里面的数据每次的是最新的
  }
  update() {
    if (this.node.nodetype === 3) {
      this.node.nodevalue = this.vm.data[this.name] //去data 里面查找对应的 数据并赋值给对应 元素
    } else if (this.node.nodetype === 1) {
      this.node.value = this.vm.data[this.name]
    }
  }
}

  

如您对本文有疑问或者有任何想说的,请 点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网