亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么使用Object.defineProperty實現簡易的vue功能

發布時間:2023-04-20 15:53:29 來源:億速云 閱讀:99 作者:iii 欄目:開發技術

這篇“怎么使用Object.defineProperty實現簡易的vue功能”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“怎么使用Object.defineProperty實現簡易的vue功能”文章吧。

vue 雙向綁定的原理

實現 vue 的雙向綁定,v-textv-modelv-on 方法

Vue 響應系統,其核心有三點:observe、watcher、dep

  • observe:遍歷 data 中的屬性,使用 Object.definePropertyget/set 方法- 對其進行數據劫持;

  • dep:每個屬性擁有自己的消息訂閱器 dep,用于存放所有訂閱了該屬性的觀察者對象;

  • watcher:觀察者(對象),通過 dep 實現對響應屬性的監聽,監聽到結果后,主動觸發自己的回調進行響應。

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 => {
      /*
       *當value值為基本數據類型時,this.key數據變化,對用的$data不會變化
       *只有當value值為對象或者數組類型時,數據變化會同步
       **/
      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();
    // 當value為對象時,遞歸調用
    this.work(value);
    /*
     *當一個變量需要影響多個元素時,即一個變量變化需要響應多個元素內容的變化
     *先記錄下所有的依賴
     */
    Object.defineProperty(data, key, {
      enumerable: true,
      configurable: true,
      get: () => {
        if (Dep.target) {
          dep.add(Dep.target);
        }
        return value;
      },
      set: newValue => {
        value = newValue;
        // 賦新值后,新值有可能為對象,重新綁定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;
    // 會觸發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)) {
          // 根據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));
    }
  }
}

測試 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">
      <h4>{{ msg }}</h4>
      <p>{{ count }}</p>
      <h2>v-text</h2>
      <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實現簡易的vue功能”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

灵石县| 朔州市| 自治县| 准格尔旗| 青阳县| 新巴尔虎左旗| 中宁县| 晴隆县| 桦南县| 渭南市| 藁城市| 高唐县| 页游| 玉林市| 拜城县| 樟树市| 雷山县| 阜平县| 武平县| 聊城市| 大余县| 咸丰县| 渝北区| 柳州市| 扶绥县| 宁波市| 枞阳县| 鞍山市| 深泽县| 中卫市| 浠水县| 瑞昌市| 方山县| 措美县| 嘉兴市| 保定市| 旺苍县| 尤溪县| 定边县| 乌拉特前旗| 尚义县|