vue.js 双向数据绑定的实现


vue.js 双向数据绑定的实现

1.首先定义构造函数

var Vue = function (params) { 
  this.el = document.getElementById(params.el) 
  this.data = params.data 
  this.init() 
} 
Vue.prototype = { 
  init: function () { 
    this.updateView() 
    this.bindData() 
    this.bindModel() 
  } 
} 

 

2.在初始化方法中先定义一个视图的更新方法。这样一个简单的单向绑定就已经实现了。

Vue.prototype.updateView = function () {
  // v-text 视图更新
  var doms = this.el.querySelectorAll('[v-text]')
  for (var i = 0; i < doms.length; i++) {
    var bindName = doms[i].getAttribute('v-text')
    doms[i].innerHTML = this.data[bindName]
  }
  // v-model 视图更新
  var modelDoms = this.el.querySelectorAll('[v-model]')
  for (var i = 0; i < modelDoms.length; i++) {
    var modelBindName = modelDoms[i].getAttribute('v-model')
    modelDoms[i].value = this.data[modelBindName] || ''
  }
}

 

3.然后要建立数据层到视图层的单向联系。

Vue.prototype.bindData = function () {
  var data = this.data
  for (var key in data) {
    this.defineObject(data, key, data[key])
  }
}
Vue.prototype.defineObject = function (obj, prop, value) {
  var value = value || ''
  var _that = this
  Object.defineProperty(obj, prop, {
    get: function () {
      return value
    },
    set: function (newVal_) {
      value = newVal_
      _that.updateView()
    }
  })
}

 

4.建立视图层到数据层的联系。也就是v-model的实现。
 

// model数据绑定
Vue.prototype.bindModel = function () {
  var data = this.data
  var _that = this
  var doms = this.el.querySelectorAll('[v-model]')
  for (var i = 0; i < doms.length; i++) {
  var bindName = doms[i].getAttribute('v-model')
    doms[i].value = data[bindName] || ''
    if (document.addEventListener) {
      doms[i].addEventListener('keyup', function (event) {
        e = event || window.event
        data[bindName] = e.target.value
      }, false)
    } else {
      doms[i].attachEvent('onkeyup', function (event) {
        e = event || window.event
        data[bindName] = e.target.value
      }, false)
    }
  }
}

 

至此一个简单的双向数据绑定就已经实现了。

详细demo。

<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
    <div id="vueTest">
        <input type="text" name="cc" v-model="test1">
        <div v-text="test1"></div>
        <div v-text="test1"></div>
        <div v-text="test2"></div>
    </div>
</body>
    <script type="text/javascript">
        var Vue = function (params) {
            this.el = document.getElementById(params.el)
            this.data = params.data
            this.init()
        }

        Vue.prototype = {
            init: function () {
                this.updateView()
                this.bindData()
                this.bindModel()
            },
            // 更新视图
            updateView: function () {
                // v-text 视图更新
                var doms = this.el.querySelectorAll('[v-text]')
                for (var i = 0; i < doms.length; i++) {
                    var bindName = doms[i].getAttribute('v-text')
                    doms[i].innerHTML = this.data[bindName]
                }
                // v-model 视图更新
                var modelDoms = this.el.querySelectorAll('[v-model]')
                for (var i = 0; i < modelDoms.length; i++) {
                    var modelBindName = modelDoms[i].getAttribute('v-model')
                    modelDoms[i].value = this.data[modelBindName] || ''
                }
            },
            // 数据绑定
            bindData: function () {
                var data = this.data
                for (var key in data) {
                    this.defineObject(data, key, data[key])
                }
            },
            // model数据绑定
            bindModel: function () {
                var data = this.data
                var _that = this
                var doms = this.el.querySelectorAll('[v-model]')
                for (var i = 0; i < doms.length; i++) {
                    var bindName = doms[i].getAttribute('v-model')
                    doms[i].value = data[bindName] || ''
                    if (document.addEventListener) {
                        doms[i].addEventListener('keyup', function (event) {
                            e = event || window.event
                            data[bindName] = e.target.value
                        }, false)
                    } else {
                        doms[i].attachEvent('onkeyup', function (event) {
                            e = event || window.event
                            data[bindName] = e.target.value
                        }, false)
                    }
                }
            },
            // 数据劫持
            defineObject: function (obj, prop, value) {
                var value = value || ''
                var _that = this
                Object.defineProperty(obj, prop, {
                    get: function () {
                        return value
                    },
                    set: function (newVal_) {
                        value = newVal_
                        _that.updateView()
                    }
                })
            },
        }

        var vue = new Vue({
            el: 'vueTest',
            data: {
                test1: 'this is a test',
                test2: 'this is a test2'
            }
        })

        // 测试用
        setTimeout(function () {
            vue.data.test1 = '5 second delay'
        }, 5000)
    </script>
</html>

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM