实现乞丐版vue

由于工作中经常使用vue,所以对它的内部构造非常着迷,一直想探究其究竟。也看了不少文章,无奈水平所限并不能吃透、看透。所以运用目前自己所学,写了demo,本demo总共100行左右,实现v-model,v-bind,v-click等功能。

由于水平所限,本demo写的不是很规范,考虑的不是很周全,程序设计不太合理。只能实现基本的功能,作为学习的一个记录。还希望大神勿喷,欢迎批评指正。

第一次写博客,语言组织能力有待加强。

 

1、HTML部分  

<div id="app">
    <span style="display: inline-block" v-bind="num"></span>
    <span style="display: block" v-bind="input"></span>
    <span style="display: block" v-bind="test"></span>
    <span style="display: block" v-bind="input2"></span>
    <input style="display: block" type="text" v-model="input">
    <input style="display: block" type="text" v-model="test">
    <input style="display: block" type="text" v-model="input2">
  <button @click="handleClick">click</button>
</div>

2、javascript部分

<script>
  function Vue (options) {
    this.initValue = Object.assign({},options.data)
    this.data = options.data
    this.methods = options.methods
    this.el = document.getElementById(options.el)
    this.bindList = []
    this._init(this.el)
  }
  Vue.prototype._init = function (d) {
      this.render(d.children)
      this.definedProprtyInt (this.data)
  }
  //遍历dom树
  Vue.prototype.render =function (nodeList) {
      Array.prototype.forEach.call(nodeList,(item) => {
         let childNode = item.children
         let len = childNode.length
         //匹配v-model或者@model
          let model = item.getAttribute('v-model')||item.getAttribute('@model')
          let type = item.tagName.toLocaleLowerCase()
          if (model) {
            item.value = this.initValue[model]
            this.data[model] = ""
            if (type === 'input') {
              item.onkeyup = function (e) {
                this.data[model] = e.target.value
              }.bind(this)
            }
          }
          //匹配v-bind 并绑定相应的值
          let bind = item.getAttribute('v-bind')||item.getAttribute('@bind')
          if(bind && (bind in this.data)) {
           //收集依赖
              item.innerHTML = this.initValue[bind]
            this.bindList.push({
                key:bind,
                d:item
            })

          }
          //匹配v-click或者@click
          let eventName =  item.getAttribute('v-click')||item.getAttribute('@click')
          if(eventName) {
            item.onclick = function (e) {
              this.methods[eventName].bind(this.data)(e)
            }.bind(this)
          }
         if(len>0) {
           this.render(childNode)
         }
      },this)
  }
  Vue.prototype.definedProprtyInt = function (o){
      let _this = this
    for(let key in o) {
      Object.defineProperty(o,key,{
        set:function (v) {
          //在data中找到相应的key渲染到对应的页面上
          this.bindList.forEach((item) => {
            if(key == item.key) {
                item.d.innerHTML = v
            }
          })
            _this.initValue[key] = v
        }.bind(this),
        get:function (v) {
            // console.log(_this.initValue[key])
         return _this.initValue[key]
        },
      })
    }
  }
  new Vue({
    el:"app",
    data:{
      input:"input",
      test:"test",
      input2:"input2",
      num:1
    },
    methods:{
      handleClick:function (e) {
          this.num ++
      }
    }
  })
</script>

 

posted @ 2018-07-17 16:53  木鱼汀  阅读(165)  评论(0编辑  收藏  举报