欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解如何使用Object.defineProperty實(shí)現(xiàn)簡(jiǎn)易的vue功能

 更新時(shí)間:2023年04月20日 11:47:32   作者:你這個(gè)年齡怎么睡得著的  
這篇文章主要為大家介紹了如何使用Object.defineProperty實(shí)現(xiàn)簡(jiǎn)易的vue功能示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

vue 雙向綁定的原理

實(shí)現(xiàn) vue 的雙向綁定,v-text、v-modelv-on 方法

Vue 響應(yīng)系統(tǒng),其核心有三點(diǎn):observe、watcher、dep

  • observe:遍歷 data 中的屬性,使用 Object.definePropertyget/set 方法- 對(duì)其進(jìn)行數(shù)據(jù)劫持;
  • dep:每個(gè)屬性擁有自己的消息訂閱器 dep,用于存放所有訂閱了該屬性的觀察者對(duì)象;
  • watcher:觀察者(對(duì)象),通過 dep 實(shí)現(xiàn)對(duì)響應(yīng)屬性的監(jiān)聽,監(jiān)聽到結(jié)果后,主動(dòng)觸發(fā)自己的回調(diào)進(jìn)行響應(yīng)。
class MinVue {
  constructor(options) {
    this.$data = options.data;
    this.$methods = options.methods;
    this.$el = typeof options.el === 'string' ? document.querySelector(options.el) : el;
    this.bindData(this.$data);
    new Observer(this.$data);
    new Compile(this);
  }
  bindData(data) {
    Object.keys(data).forEach(key => {
      /*
       *當(dāng)value值為基本數(shù)據(jù)類型時(shí),this.key數(shù)據(jù)變化,對(duì)用的$data不會(huì)變化
       *只有當(dāng)value值為對(duì)象或者數(shù)組類型時(shí),數(shù)據(jù)變化會(huì)同步
       **/
      Object.defineProperty(this, key, {
        enumerable: true,
        configurable: true,
        get: () => {
          return data[key];
        },
        set: newValue => {
          data[key] = newValue;
        },
      });
    });
  }
}
class Observer {
  constructor(data) {
    this.work(data);
  }
  work(data) {
    if (Object.prototype.toString.call(data) === '[object Object]') {
      Object.keys(data).forEach(key => {
        this.defineReactive(data, key, data[key]);
      });
    }
  }
  defineReactive(data, key, value) {
    const observer = this;
    const dep = new Dep();
    // 當(dāng)value為對(duì)象時(shí),遞歸調(diào)用
    this.work(value);
    /*
     *當(dāng)一個(gè)變量需要影響多個(gè)元素時(shí),即一個(gè)變量變化需要響應(yīng)多個(gè)元素內(nèi)容的變化
     *先記錄下所有的依賴
     */
    Object.defineProperty(data, key, {
      enumerable: true,
      configurable: true,
      get: () => {
        if (Dep.target) {
          dep.add(Dep.target);
        }
        return value;
      },
      set: newValue => {
        value = newValue;
        // 賦新值后,新值有可能為對(duì)象,重新綁定get set方法
        observer.work(newValue);
        dep.notify();
      },
    });
  }
}
class Dep {
  constructor() {
    this.watcher = new Set();
  }
  add(watcher) {
    if (watcher && watcher.update) this.watcher.add(watcher);
  }
  notify() {
    this.watcher.forEach(watch => watch.update());
  }
}
class Watcher {
  constructor(vm, key, cb) {
    Dep.target = this;
    this.vm = vm;
    this.key = key;
    // 會(huì)觸發(fā)Observer定義的getter方法,收集Dep.target
    this._old = vm.$data[key];
    this.cb = cb;
    Dep.target = null;
  }
  update() {
    const newValue = this.vm.$data[this.key];
    this.cb(newValue);
    this._old = newValue;
  }
}
class Compile {
  constructor(vm) {
    this.vm = vm;
    this.methods = vm.$methods;
    this.compile(vm.$el);
  }
  compile(el) {
    const childNodes = el.childNodes;
    Array.from(childNodes).forEach(node => {
      if (this.isTextNode(node)) {
        this.compileTextNode(node);
      } else if (this.isElementNode(node)) {
        this.compileElement(node);
      }
      if (node.childNodes && node.childNodes.length) this.compile(node);
    });
  }
  isTextNode(node) {
    return node.nodeType === 3;
  }
  isElementNode(node) {
    return node.nodeType === 1;
  }
  compileTextNode(node) {
    // .+?正則懶惰匹配
    const reg = /\{\{(.+?)\}\}/g;
    const text = node.textContent;
    if (reg.test(text)) {
      let key = RegExp.$1.trim();
      node.textContent = text.replace(reg, this.vm[key]);
      new Watcher(this.vm, key, newValue => {
        node.textContent = newValue;
      });
    }
  }
  compileElement(node) {
    const attrs = node.attributes;
    if (attrs.length) {
      Array.from(attrs).forEach(attr => {
        if (this.isDirective(attr.name)) {
          // 根據(jù)v-來截取一下后綴屬性名
          let attrName = attr.name.indexOf(':') > -1 ? attr.name.substr(5) : attr.name.substr(2);
          let key = attr.value;
          this.update(node, attrName, key, this.vm[key]);
        }
      });
    }
  }
  isDirective(dir) {
    return dir.startsWith('v-');
  }
  update(node, attrName, key, value) {
    if (attrName === 'text') {
      node.textContent = value;
      new Watcher(this.vm, key, newValue => {
        node.textContent = newValue;
      });
    } else if (attrName === 'model') {
      node.value = value;
      new Watcher(this.vm, key, newValue => {
        node.value = newValue;
      });
      node.addEventListener('input', e => {
        this.vm[key] = node.value;
      });
    } else if (attrName === 'click') {
      node.addEventListener(attrName, this.methods[key].bind(this.vm));
    }
  }
}

測(cè)試 MinVue

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="app">
      <h3>{{ msg }}</h3>
      <p>{{ count }}</p>
      <h1>v-text</h1>
      <p v-text="msg"></p>
      <input type="text" v-model="count" />
      <button type="button" v-on:click="increase">add+</button>
      <button type="button" v-on:click="changeMessage">change message!</button>
      <button type="button" v-on:click="recoverMessage">recoverMessage!</button>
    </div>
  </body>
  <script src="./js/min-vue.js"></script>
  <script>
    new MinVue({
      el: '#app',
      data: {
        msg: 'hello,mini vue.js',
        count: 666,
      },
      methods: {
        increase() {
          this.count++;
        },
        changeMessage() {
          this.msg = 'hello,eveningwater!';
        },
        recoverMessage() {
          console.log(this);
          this.msg = 'hello,mini vue.js';
        },
      },
    });
  </script>
</html>

以上就是詳解如何使用Object.defineProperty實(shí)現(xiàn)簡(jiǎn)易的vue功能的詳細(xì)內(nèi)容,更多關(guān)于Object.defineProperty vue的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論