美文网首页
一个简易的双向绑定demo

一个简易的双向绑定demo

作者: 苍老师的眼泪 | 来源:发表于2022-04-04 23:47 被阅读0次
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
    </head>
    
    <body>
    
      <div id="app">
        <div>
          一个叫<strong>{{ name }}</strong>的人,他今年
          <strong>{{ age }}</strong>岁,
          家住在<strong>{{ home.location }}</strong>
          他有一个朋友也是 <strong> {{ age }}</strong> 岁
        </div>
      </div>
    
      <script>
        let data = {
          name: "Edison",
          age: 26,
          home: {
            location: 'Guangdong'
          }
        }
        let el = "#app"
    
        let vm = {
        
        }
    
    
        function reactive(target, obj) {
    
          for (let key of Object.keys(obj)) {
    
            if (typeof obj[key] == 'object') {
              vm[key] = {}
              reactive(vm[key], obj[key])
              return
            }
    
            // 记录依赖的watcher
            let dep = []
    
            Object.defineProperty(target, key, {
              get: function () {
    
                if (global_watcher) {
                  dep.push(global_watcher)
                }
    
                return obj[key]
              },
              set: function (val) {
    
                // console.log('哈哈, ' + key + '的值为:' + val)
                
                obj[key] = val
    
                dep.forEach(element => {
    
                  element.update(val)
                });
              }
            })
          }
    
        }
    
        let global_watcher = null
      
        reactive(vm, data)
    
        class Watcher {
          constructor(node) {
            this.node = node
          }
          update(new_value) {
            
            this.node.textContent = new_value
          }
        }
    
        compile(el)
    
        function compile(root) {
          let root_node = document.querySelector(root)
    
          compile_node(root_node)
    
        }
    
        function compile_node(node) {
          if (node.nodeType == 1) {
            // 元素节点
    
            node.childNodes.forEach(child => {
              compile_node(child)
            })
    
          } else if (node.nodeType == 3) {
            // 文本节点
    
            let reg_exp = /\{\{(.*)\}\}/
    
            if (reg_exp.test(node.textContent)) {
              let exp = RegExp.$1.trim()
    
              // 怎么才能放到 exp 属性对应的dep里面呢?
              // 通过触发getter和setter来访问相应的dep
              
              global_watcher = new Watcher(node.parentNode)
              // 触发一下相应的getter, 以便在get中将watcher加入刀相应的dep
              // 顺便改一下相应html节点的值
              node.textContent = get_value(vm, exp)
    
              global_watcher = null
    
            }
    
          } else 
            throw '暂时考虑别的类型的节点'
          
    
        }
    
      
        function get_value(vm, exp) {
    
          let value = vm
    
          exp.split('.').forEach(e => {
            value = value[e]
          })
    
          return value
        }
    
        
    
      </script>
    
    </body>
    
    </html>
    

    相关文章

      网友评论

          本文标题:一个简易的双向绑定demo

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