vue 生命周期LIFECYCLE源碼

var LIFECYCLE_HOOKS = [
  'beforeCreate',
  'created',
  'beforeMount',
  'mounted',
  'beforeUpdate',
  'updated',
  'beforeDestroy',
  'destroyed',
  'activated',
  'deactivated',
  'errorCaptured',
  'serverPrefetch'
];

生命周期就是數(shù)據(jù)流在某個(gè)時(shí)間點(diǎn)通過callHook調(diào)用vm.$options對(duì)應(yīng)的LIFECYCLE_HOOKS函數(shù)方法

function callHook (vm, hook) {
  // #7573 disable dep collection when invoking lifecycle hooks
 ......
  if (vm._hasHookEvent) {
    vm.$emit('hook:' + hook);
  }
 ......
}
image.png

利用這張圖來對(duì)應(yīng)源碼并淋,查看和周期的過程给梅,會(huì)比較有邏輯性些

一假丧、beforeCreate 和 created

new Vue()也就是是執(zhí)行源碼中的_init函數(shù)

可以查看beforeCreate前的工作,created前的工作

function initMixin (Vue) {
  Vue.prototype._init = function (options) {
    ......
    initLifecycle(vm);
    initEvents(vm);
    initRender(vm);
    callHook(vm, 'beforeCreate');

    initInjections(vm); // resolve injections before data/props
    initState(vm);
    initProvide(vm); // resolve provide after data/props
    callHook(vm, 'created');
    ......
  }
}

二动羽、接下來查看下一步 Has 'el' options?

function initMixin (Vue) {
  Vue.prototype._init = function (options) {
    ......
    if (vm.$options.el) {
      vm.$mount(vm.$options.el);
    }
  }
}

1.如果有el屬性包帚,則會(huì)執(zhí)行源碼中的上面代碼

// options中有'el'屬性
new Vue({
  el:'#app',
  render: h => h(App)
})

2.如果沒有el屬性,則直接執(zhí)行vm.$mount函數(shù)進(jìn)行掛載

new Vue({
  render: h => h(App)
}).$mount("#app")

上面的有el屬性和無el屬性最終都會(huì)執(zhí)行vm.$mount函數(shù)

// public mount method
Vue.prototype.$mount = function (
  el,
  hydrating
) {
  el = el && inBrowser ? query(el) : undefined;
  return mountComponent(this, el, hydrating)
};

三、beforeMount 和 mounted

function mountComponent (
  vm,
  el,
  hydrating
) {
  vm.$el = el;
  if (!vm.$options.render) {
    vm.$options.render = createEmptyVNode;
  }
  ......
  callHook(vm, 'beforeMount');
  ......
  // manually mounted instance, call mounted on self
  // mounted is called for render-created child components in its inserted hook
  if (vm.$vnode == null) {
    vm._isMounted = true;
    callHook(vm, 'mounted');
  }
  return vm
}

1.調(diào)用beforeMount之間运吓,vm.$options.render函數(shù)首次被調(diào)用

2.vm.$el= el el賦值給vm.$el并掛載到實(shí)例上渴邦,mounted之后我們會(huì)看到實(shí)例中存在一個(gè)

vm.$el= el

問題:vm.$options.render函數(shù)調(diào)用作用?拘哨?谋梭?

實(shí)例化Vue時(shí),可以直接用render函數(shù)轉(zhuǎn)讓化component并掛載

四、beforeUpdate 和 updated

  // we set this to vm._watcher inside the watcher's constructor
  // since the watcher's initial patch may call $forceUpdate (e.g. inside child
  // component's mounted hook), which relies on vm._watcher being already defined
  new Watcher(vm, updateComponent, noop, {
    before: function before () {
      if (vm._isMounted && !vm._isDestroyed) {

        callHook(vm, 'beforeUpdate');
      }
    }
  }, true /* isRenderWatcher */);

Watcher在mounted時(shí)倦青,就實(shí)例化了瓮床,因?yàn)槌跏蓟痙om結(jié)構(gòu)時(shí)會(huì)調(diào)用$forceUpdate

  Vue.prototype.$forceUpdate = function () {
    var vm = this;
    if (vm._watcher) {
      vm._watcher.update();
    }
  };

而調(diào)用$forceUpdate時(shí)會(huì)用到vm._watcher

var Watcher = function Watcher (
  vm,
  expOrFn,
  cb,
  options,
  isRenderWatcher
) {
  this.vm = vm;
  if (isRenderWatcher) {
    vm._watcher = this;
  }
...
}

上面代碼可以看到實(shí)例化Watcher時(shí) vm._watcher = this; this指的是當(dāng)前的Watcher的函數(shù),也就是說Watcher.prototype值产镐,vm._watcher也同樣繼承到了隘庄,可以訪問

vm._watcher.update() 實(shí)際上訪問的也就是Watcher.prototype.update

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

queueWatcher -> flushSchedulerQueue -> callUpdatedHooks
可以看到callHook(vm, 'updated');

function callUpdatedHooks (queue) {
  var i = queue.length;
  while (i--) {
    var watcher = queue[i];
    var vm = watcher.vm;
    if (vm._watcher === watcher && vm._isMounted && !vm._isDestroyed) {
      callHook(vm, 'updated');
    }
  }
}

五、beforeDestroy 和 destroyed

1.實(shí)例銷毀之間調(diào)用beforeDestroy, beforeDestroy調(diào)用時(shí)癣亚,實(shí)例還是能繼續(xù)使用

2.調(diào)用destroyed后丑掺,說明實(shí)例已經(jīng)銷毀。那么實(shí)例指向的所有事件逃糟,子實(shí)例都會(huì)解綁吼鱼,也就不能再使用了

Vue.prototype.$destroy = function () {
    var vm = this;
    if (vm._isBeingDestroyed) {
      return
    }
    callHook(vm, 'beforeDestroy');
    vm._isBeingDestroyed = true;
    .....
    callHook(vm, 'destroyed');
  };

六、activated 和 deactivated

insert -> activateChildComponent -> callHook(vm, 'activated');
在insert函數(shù)中我們看到條件vnode.data.keepAlive

keep-alive激活時(shí)使用

  insert: function insert (vnode) {
   ......
    if (vnode.data.keepAlive) {
      if (context._isMounted) {
        // vue-router#1212
        // During updates, a kept-alive component's child components may
        // change, so directly walking the tree here may call activated hooks
        // on incorrect children. Instead we push them into a queue which will
        // be processed after the whole patch process ended.
        queueActivatedComponent(componentInstance);
      } else {
        activateChildComponent(componentInstance, true /* direct */);
      }
    }
  },
function activateChildComponent (vm, direct) {
  ......
  if (vm._inactive || vm._inactive === null) {
    ......
    callHook(vm, 'activated');
  }
}

keep-alive不激活時(shí)使用绰咽,也就是當(dāng)前有兩個(gè)路由A,B并且顯示內(nèi)容在keep-alive中

1.A,B顯示的內(nèi)容會(huì)被keep-alive緩存
2.當(dāng)前A,如果點(diǎn)擊路由顯示B,則A會(huì)走destroy函數(shù)菇肃,會(huì)觸發(fā)deactivated
<template>
  <div id="app1">
    <keep-alive>
        <router-view></router-view>
    </keep-alive>
    <router-link to="/A">Go to Foo</router-link>
    <router-link to="/B">Go to Bar</router-link>
</template>

destroy -> deactivateChildComponent -> callHook(vm, 'deactivated');

destroy: function destroy (vnode) {
    var componentInstance = vnode.componentInstance;
    if (!componentInstance._isDestroyed) {
      if (!vnode.data.keepAlive) {
        componentInstance.$destroy();
      } else {
        deactivateChildComponent(componentInstance, true /* direct */);
      }
    }
  }

function deactivateChildComponent (vm, direct) {
  if (direct) {
    vm._directInactive = true;
    if (isInInactiveTree(vm)) {
      return
    }
  }
  if (!vm._inactive) {
    vm._inactive = true;
    for (var i = 0; i < vm.$children.length; i++) {
      deactivateChildComponent(vm.$children[i]);
    }
    callHook(vm, 'deactivated');
  }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市取募,隨后出現(xiàn)的幾起案子琐谤,更是在濱河造成了極大的恐慌,老刑警劉巖玩敏,帶你破解...
    沈念sama閱讀 222,000評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件斗忌,死亡現(xiàn)場離奇詭異,居然都是意外死亡旺聚,警方通過查閱死者的電腦和手機(jī)织阳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來砰粹,“玉大人唧躲,你說我怎么就攤上這事。” “怎么了弄痹?”我有些...
    開封第一講書人閱讀 168,561評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵饭入,是天一觀的道長。 經(jīng)常有香客問我肛真,道長谐丢,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,782評(píng)論 1 298
  • 正文 為了忘掉前任蚓让,我火速辦了婚禮乾忱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘凭疮。我一直安慰自己饭耳,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評(píng)論 6 397
  • 文/花漫 我一把揭開白布执解。 她就那樣靜靜地躺著寞肖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪衰腌。 梳的紋絲不亂的頭發(fā)上新蟆,一...
    開封第一講書人閱讀 52,394評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音右蕊,去河邊找鬼琼稻。 笑死,一個(gè)胖子當(dāng)著我的面吹牛饶囚,可吹牛的內(nèi)容都是我干的帕翻。 我是一名探鬼主播,決...
    沈念sama閱讀 40,952評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼萝风,長吁一口氣:“原來是場噩夢啊……” “哼嘀掸!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起规惰,我...
    開封第一講書人閱讀 39,852評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤睬塌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后歇万,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體揩晴,經(jīng)...
    沈念sama閱讀 46,409評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評(píng)論 3 341
  • 正文 我和宋清朗相戀三年贪磺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了硫兰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,615評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡寒锚,死狀恐怖劫映,靈堂內(nèi)的尸體忽然破棺而出呻粹,到底是詐尸還是另有隱情,我是刑警寧澤苏研,帶...
    沈念sama閱讀 36,303評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站腮郊,受9級(jí)特大地震影響摹蘑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜轧飞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評(píng)論 3 334
  • 文/蒙蒙 一衅鹿、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧过咬,春花似錦大渤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至衔掸,卻和暖如春烫幕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背敞映。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評(píng)論 1 272
  • 我被黑心中介騙來泰國打工较曼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人振愿。 一個(gè)月前我還...
    沈念sama閱讀 49,041評(píng)論 3 377
  • 正文 我出身青樓捷犹,卻偏偏與公主長得像,于是被迫代替她去往敵國和親冕末。 傳聞我的和親對(duì)象是個(gè)殘疾皇子萍歉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評(píng)論 2 359