• vue 数据双向绑定 实现逻辑


    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]
        }
      }
    }
    

      

  • 相关阅读:
    Bitstream or PCM?
    centos7安装Redis-3.2.8
    【生肉】【不义联盟
    ES6中Map数据结构学习笔记
    机器学习基石入门
    2019/5/9 长难句
    文件遍历选取脚本
    [JS奇怪的世界]No.55 危險小叮嚀:陣列與for in
    OpenGL Panorama Player
    吴裕雄--天生自然MySQL学习笔记:MySQL 连接
  • 原文地址:https://www.cnblogs.com/SuperBrother/p/12779161.html
Copyright © 2020-2023  润新知