美文网首页
Vue响应原理

Vue响应原理

作者: O8 | 来源:发表于2017-09-25 10:20 被阅读0次

    Vue 的响应依赖于Object.defineProperty,这也是Vue不支持IE8的原因。Vue通过设定对象属性的setter/getter方法来监听数据的变化。通过getter进行依赖收集,而每个setter方法就是一个观察者,在数据变更的时候通知订阅者更新视图。


    看看简单的双向绑定实现

    const obj = {
    
    object.defineProperty(obj, 'hello', {
      get(value) {
        console.log('use get')
      },
      set(newVal, oldVal) {
        console.log('user')
      }
    
    
    <input type="text" id="a"/>
    <span id="b"></span>
    
    <script>
        const obj = {};
        Object.defineProperty(obj,'hello',{
          get(){
            console.log("啦啦啦,方法被调用了");
          },
          set(newVal){
            document.getElementById('a').value = newVal;
            document.getElementById('b').innerHTML = newVal;
          }
        })
        document.addEventListener('keyup',function(e){
          obj.hello = e.target.value;
        })
    </script>
    

    将数据data变成可观察(observable)

    function observer(val) {
      Object
        .key
        .forEach((val) => {
           defineReactive(val, key, value[key], cb)
        })
    }
    function defineReactive(obj, key, val, cb) {
      Object.defineProperty(obj, key, {
          enumerable: true,
          configurable: true,
          get: () => {
            /*....依赖收集等....*/
                /*Github:https://github.com/answershuto*/
          },
          set: newVal => {
            cb();/*订阅者收到消息的回调*/
          }
       })
    }
    class Vue {
       constructor(options) {
          this._data = options.data;
          observer(this._data, options.render)
        }
     }
    let app = new Vue({
        el: '#app',
        data: {
            text: 'text',
            text2: 'text2'
        },
        render(){
            console.log("render");
        }
    })
    

    为了便于理解,首先考虑一种最简单的情况,不考虑数组等情况,代码如上所示。在initData中会调用observe这个函数将Vue的数据设置成observable的。当_data数据发生改变的时候就会触发set,对订阅者进行回调(在这里是render)。

    那么问题来了,需要对app._date.text操作才会触发set。为了偷懒,我们需要一种方便的方法通过app.text直接设置就能触发set对视图进行重绘。那么就需要用到代理。

    代理

    我们可以在Vue的构造函数constructor中为data执行一个代理proxy。这样我们就把data上面的属性代理到了vm实例上。

    _proxy(options.data);/*构造函数中*/
    
    /*代理*/
    function _proxy (data) {
       const that = this;
       Object.keys(data).forEach(key => {
           Object.defineProperty(that, key, {
               configurable: true,
               enumerable: true,
               get: function proxyGetter () {
                   return that._data[key];
               },
               set: function proxySetter (val) {
                   that._data[key] = val;
               }
           })
       });
    }
    

    我们就可以用app.text代替app._data.text了。

    下面是一个模拟Vue数据绑定的方法


    vue.png

    (转)

    相关文章

      网友评论

          本文标题:Vue响应原理

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