自制最簡易版vue.js

adong搬砖發表於2024-08-19
 class MyVue {
  constructor(options) {
    this.$el = document.querySelector(options.el)
    this.$data = options.data
    this.$methods = options.methods
    this.init()
    this.compile(this.$el)
  }

  compile (node) {
    let that = this
    node.childNodes.forEach(item => {
      if (item.nodeType == 1) {
        for (let i = 0; i < item.attributes.length; i++) {
          if (Array.from(item.attributes).some(items => items.localName.startsWith('@'))) {
            const attrNode = item.attributes[i]
            if (attrNode.localName.startsWith('@')) {
              const evname = attrNode.localName.slice(1)
              item['on' + evname] = this[item.getAttribute('@' + evname).trim()].bind(this)
            }
          }
        }

        if (item.hasAttribute('vModel') && item.tagName == 'INPUT') {
          const dataProp = item.getAttribute('vModel').trim()
          item.value = this[dataProp]
          if (!item.SecondAddEventListener) {
            item.SecondAddEventListener = true
            item.addEventListener('input', (e) => {
              this[dataProp] = e.target.value
            })
          }
        }

        Array.from(item.attributes).filter(entry => entry.localName !== 'vmodel' && !entry.localName.startsWith('@')).forEach(entry => {
          if (entry.localName.startsWith('disabled')) {
            if (entry.localName == 'disabled') {

              const dataName = item.getAttribute('disabled').trim()
              if (!that[dataName]) {
                item.disabled = false
                item.setAttribute('disabledfalse', dataName)
              }
            } else {
              const dataName = item.getAttribute('disabledfalse')
              if (that[dataName]) {
                item.setAttribute('disabled', dataName)
              }
            }
          } else {
            const dataName = item.getAttribute(entry.localName).trim()
            item.setAttribute(entry.localName, that[dataName] == undefined ? dataName : that[dataName])
          }


        })

        if (item.childNodes.length > 0) {
          this.compile(item)
        }

      }


      if (item.nodeType == 3) {
        let text
        if (item.isSecondMatch) {
          text = item.FirstContent
        } else {
          text = item.textContent.trim()
          item.FirstContent = text
        }
        const reg = /\{\{(.*?)\}\}/g
        const newText = text.replace(reg, (_, b) => {
          item.isSecondMatch = true
          return this.$data[b]
        })
        item.textContent = newText
      }
    })
  }

  init () {
    const vm = this
    const obj = Object.assign(vm.$data, vm.$methods)
    for (let k in obj) {
      Object.defineProperty(vm, k, {
        get () {
          if (typeof vm.$methods[k] == 'function') return vm.$methods[k]
          return vm.$data[k]
        },
        set (newVal) {
          vm.$data[k] = newVal
          vm.compile(vm.$el)
        }
      })
    }
  }
}

相關文章