最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Vue收集依賴與觸發(fā)依賴源碼刨析

 更新時間:2022年10月21日 14:44:16   作者:Young soul2  
vue對依賴的管理使用的是發(fā)布訂閱者模式,其中watcher扮演訂閱者,Dep扮演發(fā)布者。所以dep中會有多個watcher,一個訂閱者也可以有多個發(fā)布者(依賴)。總共三個過程:定義依賴、收集依賴、觸發(fā)依賴。下面開始詳細(xì)講解三個過程

定義依賴

定義依賴是什么時候開始的呢?通過源碼可以發(fā)現(xiàn)在執(zhí)行_init函數(shù)的時候會執(zhí)行initState(vm)方法:

function initState(vm) {
      ...
      if (opts.data) {
          initData(vm);
      }
      else {
          var ob = observe((vm._data = {}));
          ob && ob.vmCount++;
      }
      ...
  }

先觸發(fā)initData方法:

function initData(vm) {
      var data = vm.$options.data;
      data = vm._data = isFunction(data) ? getData(data, vm) : data || {};
      ...
      var keys = Object.keys(data);
      ...
      var i = keys.length;
      while (i--) {
          var key = keys[i];
          {
              if (methods && hasOwn(methods, key)) {
                  warn$2("Method \"".concat(key, "\" has already been defined as a data property."), vm);
              }
          }
          if (props && hasOwn(props, key)) {
              warn$2("The data property \"".concat(key, "\" is already declared as a prop. ") +
                      "Use prop default value instead.", vm);
          }
          else if (!isReserved(key)) {
              proxy(vm, "_data", key);
          }
      }
      // observe data
      var ob = observe(data);
      ob && ob.vmCount++;
  }

首先會獲取data數(shù)據(jù),然后執(zhí)行proxy(vm, “_data”, key):

var sharedPropertyDefinition = {
      enumerable: true,
      configurable: true,
      get: noop,
      set: noop
  };
function proxy(target, sourceKey, key) {
      sharedPropertyDefinition.get = function proxyGetter() {
          return this[sourceKey][key];
      };
      sharedPropertyDefinition.set = function proxySetter(val) {
          this[sourceKey][key] = val;
      };
      Object.defineProperty(target, key, sharedPropertyDefinition);
  }

在vm實例中添加了_data對象并將data的數(shù)據(jù)給了_data。隨后執(zhí)行observe(data):

function observe(value, shallow, ssrMockReactivity) {
      ...
      else if (shouldObserve &&
          (ssrMockReactivity || !isServerRendering()) &&
          (isArray(value) || isPlainObject(value)) &&
          Object.isExtensible(value) &&
          !value.__v_skip /* ReactiveFlags.SKIP */) {
          ob = new Observer(value, shallow, ssrMockReactivity);
      }
      return ob;
  }

主要執(zhí)行 new Observer(value, shallow, ssrMockReactivity)方法:

function Observer(value, shallow, mock) {
          if (shallow === void 0) { shallow = false; }
          if (mock === void 0) { mock = false; }
          this.value = value;
          this.shallow = shallow;
          this.mock = mock;
          // this.value = value
          this.dep = mock ? mockDep : new Dep();
          this.vmCount = 0;
          def(value, '__ob__', this);
          if (isArray(value)) {
             ...
          }
          else {
              /**
               * Walk through all properties and convert them into
               * getter/setters. This method should only be called when
               * value type is Object.
               */
              var keys = Object.keys(value);
              for (var i = 0; i < keys.length; i++) {
                  var key = keys[i];
                  defineReactive(value, key, NO_INIITIAL_VALUE, undefined, shallow, mock);
              }
          }
      }

主要執(zhí)行defineReactive:

function defineReactive(obj, key, val, customSetter, shallow, mock) {
      var dep = new Dep();
      var property = Object.getOwnPropertyDescriptor(obj, key);
      if (property && property.configurable === false) {
          return;
      }
      // cater for pre-defined getter/setters
      var getter = property && property.get;
      var setter = property && property.set;
      if ((!getter || setter) &&
          (val === NO_INIITIAL_VALUE || arguments.length === 2)) {
          val = obj[key];
      }
      var childOb = !shallow && observe(val, false, mock);
      Object.defineProperty(obj, key, {
          enumerable: true,
          configurable: true,
          get: function reactiveGetter() {
              var value = getter ? getter.call(obj) : val;
              if (Dep.target) {
                  {
                      dep.depend({
                          target: obj,
                          type: "get" /* TrackOpTypes.GET */,
                          key: key
                      });
                  }
                  if (childOb) {
                      childOb.dep.depend();
                      if (isArray(value)) {
                          dependArray(value);
                      }
                  }
              }
              return isRef(value) && !shallow ? value.value : value;
          },
          set: function reactiveSetter(newVal) {
              var value = getter ? getter.call(obj) : val;
              if (!hasChanged(value, newVal)) {
                  return;
              }
              if (customSetter) {
                  customSetter();
              }
              if (setter) {
                  setter.call(obj, newVal);
              }
              else if (getter) {
                  // #7981: for accessor properties without setter
                  return;
              }
              else if (!shallow && isRef(value) && !isRef(newVal)) {
                  value.value = newVal;
                  return;
              }
              else {
                  val = newVal;
              }
              childOb = !shallow && observe(newVal, false, mock);
              {
                  dep.notify({
                      type: "set" /* TriggerOpTypes.SET */,
                      target: obj,
                      key: key,
                      newValue: newVal,
                      oldValue: value
                  });
              }
          }
      });
      return dep;
  }

可以看出新增了一個依賴對象Dep,表示是該數(shù)據(jù)被哪些組件所依賴,并定義了data下數(shù)據(jù)的get和set方法。

收集依賴

vue是怎么收集依賴的呢?當(dāng)組件渲染的時候會執(zhí)行下面的渲染函數(shù):

var render = function render() {
  var _vm = this,
    _c = _vm._self._c
  return _c("div", [
    _vm._v("\n  " + _vm._s(_vm.num) + "\n  " + _vm._s(_vm.a) + "\n  "),
    _c("button", { on: { click: _vm.addModule } }, [_vm._v("新增")]),
  ])
}

原內(nèi)容如下:

<template>
  <div>
    {{num}}
    {{a}}
    <button @click="addModule">新增</button>
  </div>
</template>
<script>
export default {
  name: "TestWebpackTest",
  mounted() {
    console.log(this);
  },
  data() {
    return {
      num: 1,
      a:2
    };
  },
  computed:{
    getNum(){
      return this.num+Math.random()
    },
    getA(){
      return this.a+Math.random()
    }
  },  
  methods: {
    addModule() {
      this.num++;
    }
  }
};
</script>
<style lang="scss">
div {
  .test {
    width: 10px;
    height: 15px;
    background-color: blue;
  }
}
</style>

在渲染組件模版的時候會取獲取數(shù)據(jù),此時會觸發(fā)data中定義數(shù)據(jù)的getter方法,此時為當(dāng)前掛載組件實例化watcher的時候會設(shè)置Dep.target。

Dep.prototype.depend = function (info) {
     if (Dep.target) {
          Dep.target.addDep(this);
          if (info && Dep.target.onTrack) {
              Dep.target.onTrack(__assign({ effect: Dep.target }, info));
          }
      }
  };

通知當(dāng)前依賴的組件去添加依賴,當(dāng)前依賴的組件會將該依賴添加進(jìn)入newDeps。相反依賴也可能被多個組件使用,所以在該依賴也有多個組件。

Watcher.prototype.addDep = function (dep) {
      var id = dep.id;
      if (!this.newDepIds.has(id)) {
          this.newDepIds.add(id);
          this.newDeps.push(dep);
          if (!this.depIds.has(id)) {
              dep.addSub(this);
          }
      }
  };

其實本質(zhì)就是建立組件和變量之間的依賴關(guān)系,一個組件可以有多個依賴,一個依賴可以被多個組件使用。

觸發(fā)依賴

當(dāng)數(shù)據(jù)發(fā)生變化時會觸發(fā)數(shù)據(jù)的gettter方法:

dep.notify({
    type: "set" /* TriggerOpTypes.SET */,
    target: obj,
    key: key,
    newValue: newVal,
    oldValue: value
});

調(diào)用當(dāng)前依賴的notify方法去通知組件更新:

Dep.prototype.notify = function (info) {
 // stabilize the subscriber list first
  var subs = this.subs.slice();
...
  for (var i = 0, l = subs.length; i < l; i++) {
      if (info) {
          var sub = subs[i];
          sub.onTrigger &&
              sub.onTrigger(__assign({ effect: subs[i] }, info));
      }
      subs[i].update();
  }
};

該方法就是獲取當(dāng)前依賴下的組件并調(diào)用該組件的update方法:

Watcher.prototype.update = function () {
   /* istanbul ignore else */
    if (this.lazy) {
        this.dirty = true;
    }
    else if (this.sync) {
        this.run();
    }
    else {
        queueWatcher(this);
    }
};

下面的內(nèi)容我在另外一篇文章中講過:vue2.7.10在數(shù)據(jù)發(fā)生變化后是如何更新頁面的

總結(jié)

  • 定義依賴是在實例化組件的時候執(zhí)行的此時的Dep.target指向當(dāng)前vm實例,在initData方法中會遍歷data數(shù)據(jù)并設(shè)置get和set方法,每個數(shù)據(jù)都有一個dep(依賴),表示每個數(shù)據(jù)都會被多個組件所依賴。
  • 收集依賴是在執(zhí)行render方法的時候。該方法觸發(fā)數(shù)據(jù)的get方法,建立數(shù)據(jù)的dep(依賴)和watcher之間的聯(lián)系。
  • 觸發(fā)依賴是在數(shù)據(jù)發(fā)生改變的時候執(zhí)行。此時會觸發(fā)數(shù)據(jù)的set方法,取出當(dāng)前數(shù)據(jù)的依賴者(watcher)并循環(huán)調(diào)用依賴者的update方法更新視圖。

到此這篇關(guān)于Vue收集依賴與觸發(fā)依賴源碼刨析的文章就介紹到這了,更多相關(guān)Vue收集依賴內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 教你輕松解決Vue?Dialog彈窗詬病

    教你輕松解決Vue?Dialog彈窗詬病

    彈窗經(jīng)常被使用在一些表單的增刪改查啊,或者彈出一些提示信息等等,這篇文章主要給大家介紹了關(guān)于Vue?Dialog彈窗詬病解決的相關(guān)資料,需要的朋友可以參考下
    2023-01-01
  • vue圓形進(jìn)度條環(huán)形進(jìn)度條組件內(nèi)部顯示圖片示例

    vue圓形進(jìn)度條環(huán)形進(jìn)度條組件內(nèi)部顯示圖片示例

    這篇文章主要為大家介紹了vue圓形進(jìn)度條環(huán)形進(jìn)度條組件內(nèi)部顯示圖片示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • 詳解vue+vuex+koa2開發(fā)環(huán)境搭建及示例開發(fā)

    詳解vue+vuex+koa2開發(fā)環(huán)境搭建及示例開發(fā)

    本篇文章主要介紹了詳解vue + vuex + koa2開發(fā)環(huán)境搭建及示例開發(fā),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01
  • vue?ant?design?封裝彈窗表單的使用

    vue?ant?design?封裝彈窗表單的使用

    這篇文章主要介紹了vue?ant?design?封裝彈窗表單的使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Vue實現(xiàn)上下層疊輪播圖

    Vue實現(xiàn)上下層疊輪播圖

    這篇文章主要介紹了Vue實現(xiàn)上下層疊輪播圖,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • vue實現(xiàn)滑動解鎖功能

    vue實現(xiàn)滑動解鎖功能

    這篇文章主要為大家詳細(xì)介紹了vue實現(xiàn)滑動解鎖功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • vue實現(xiàn)動態(tài)控制el-table表格列的展示與隱藏

    vue實現(xiàn)動態(tài)控制el-table表格列的展示與隱藏

    這篇文章主要介紹了vue實現(xiàn)動態(tài)控制el-table表格列的展示與隱藏,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • vue+阿里的G2圖表-antv+折線圖實例

    vue+阿里的G2圖表-antv+折線圖實例

    這篇文章主要介紹了vue+阿里的G2圖表-antv+折線圖實例,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • Vue組合式API--setup中定義響應(yīng)式數(shù)據(jù)的示例詳解

    Vue組合式API--setup中定義響應(yīng)式數(shù)據(jù)的示例詳解

    在Vue2.x中,編寫組件的方式是使用Options API,它的特點是在對應(yīng)的屬性中編寫對應(yīng)的功能模塊,這篇文章主要介紹了Vue組合式API--setup中定義響應(yīng)式數(shù)據(jù)詳解,需要的朋友可以參考下
    2022-10-10
  • vue全局實現(xiàn)數(shù)字千位分隔符格式

    vue全局實現(xiàn)數(shù)字千位分隔符格式

    這篇文章主要為大家詳細(xì)介紹了vue全局實現(xiàn)數(shù)字千位分隔符格式,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-10-10

最新評論

三穗县| 寻乌县| 海南省| 麟游县| 房山区| 齐齐哈尔市| 鸡西市| 蒙城县| 海伦市| 建平县| 阿克| 内丘县| 福海县| 岗巴县| 江城| 宁海县| 高阳县| 镇雄县| 荆州市| 穆棱市| 临夏市| 金溪县| 鲁山县| 项城市| 桐城市| 宽城| 东源县| 宁安市| 浦北县| 老河口市| 桦川县| 麟游县| 丹东市| 九龙坡区| 建始县| 静宁县| 鞍山市| 花垣县| 郎溪县| 临高县| 黄龙县|