前言

砖搬多了就得想想怎么造砖,Vue使用多了,也得想想Vue是咋实现,Vue用着确实舒服,仔细了解一下,背后做的操作也太多了吧,但是再多的操作也是一个一个积累起来的吧!
先记录一下怎么实现data中值的渲染与修改

class Wvue extends EventTarget {
  constructor(option) {
    super()
    console.log(option)
    this.$options = option
    this.compile()
    this.observe(this.$options.data)
  }
  observe(data) {
    let keys = Object.keys(data)
    console.log(keys)
    keys.forEach(key => {
      this.defineData(data, key, data[key])
    })
  }
  // 数据劫持函数
  defineData(data, key, value) {
    let that = this
    Object.defineProperty(data, key, {
      configurable: true,
      enumerable: true,
      get() { //获取data中数据时触发
        // console.log('get数据了')
        return value
      },
      set(newValue) { //给data中数据赋值时执行
        console.log('哈哈哈,我设置数据了')

        let event = new CustomEvent(key, { //向compileNode函数中传递要改变的值
          detail: newValue
        })
        console.log(this)
        // this.dispatchEvent(event)//注意这里的this指向vm.$options.data
        that.dispatchEvent(event)
        value = newValue
      }
    })
  }
  compile() {
    let el = document.querySelector(this.$options.el)
    this.compileNode(el)
  }
  compileNode(el) {
    let childNodes = el.childNodes
    childNodes.forEach(node => {
      if (node.nodeType === 1) {
        //标签
        if (node.childNodes.length > 0) { //如果标签里还有嵌套标签或文本就继续调用
          this.compileNode(node)
        }
      } else if (node.nodeType === 3) {
        //文本节点
        console.log(node)
        let reg = /\{\{\s*(\S+)\s*\}\}/g
        let textContent = node.textContent
        console.log(textContent)
        if (reg.test(textContent)) {
          console.log('存在花括号')
          let $1 = RegExp.$1
          node.textContent = node.textContent.replace(reg, this.$options.data[$1])
          this.addEventListener($1, e => {
            console.log(e.detail)
            //这里是第二次渲染,要把新值赋值给data中的旧值
            let oldValue = this.$options.data[$1]
            // console.log(oldValue) //打印出data中的旧值
            let reg = new RegExp(oldValue)
            node.textContent = node.textContent.replace(reg, e.detail)
            //重新渲染视图
          })
        }
      }
    })
  }
}
 <div id="app">
    {{message}}
    <div class="content">
      {{htmlData}}
    </div>
  </div>
  <script src="./mvvm.js"></script>
  <script>
    let vm = new Wvue({
      el: '#app',
      data: {
        message: '加油',
        htmlData: 'hello'
      }
    })
    setTimeout(() => {
      vm.$options.data.message = '我要修改数据了'
    })
  </script>
Logo

前往低代码交流专区

更多推荐