vue中的钩子函数(二)

Vue钩子函数

在开发Vue组件时,钩子函数我们会经常用到,但是具体在什么时机,使用哪个钩子函数,会产生什么样的结果,总会模棱两可。有时某一个不好用就换另一个,好用后也不深究原因,这里就借这个机会,好好聊一聊钩子函数那些事。

生命周期图示

1. beforeCreate 和 Created

下面是Vue源码中调用beforeCreateCreated的时机

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')

从源码中可以看到,在beforeCreate之前
执行了initLifecycle, initEvents, initRender,之后才对data和props进行了注入、观测。所以 data, props, 以及与之相关的methods , watch, computedcreated之后才可以正常发挥作用。

export default {
    beforeCreate() {
        console.log(this.msg, this.sayHello); //undefined, undefined
    },
    created() {
        console.log(this.msg, this.sayHello); // hello Vue, ...
    },
    data () {
        return {
            msg: 'hello Vue'
        }
    },
    methods: {
        sayHello() {
            console.log('hello Vue');
        }
    }
}

从代码的运行结果可以看到,在beforeCreate中msg,sayHello为undefined,created中则正确输出。
了解以上差别后,我们可以在beforeCreate中做一些和data无关的操作,需要操作data可以在created中进行,比如异步获取数据后赋值。

2. beforeMonut 和 mounted

created阶段后数据观察就准备完毕了,接下来就是模版的处理。

<body>
    <div id="app">
        
    </div>
</body>
<script src='./vue.min.js'></script>
<script>
    new Vue({
        el: '#app',
        data:{
            msg: 'hello Vue'
        },
        template: '<div><span>hello Vue</span><input type="text"></div>',
        created() {
            console.log(this.$el)
            // 输出:undefined
        },
        beforeMount() {
            console.log(this.$el)
            // 输出:<div id='app'></div>
        },
        mounted() {
            console.log(this.$el)
            /*输出:<div>
                    <span>hello Vue</span><input type="text">
                   </div>*/
        }
    })
</script>

从代码的运行结果可以看出`mount`过程,在`created`中`this.$el`还为`undefined`,在beforeMount中,this.$el为Vue实例中的配置的el,并没有获得模版对应的节点。之后对模版进行编译,并用编译后的DOM替换el,插入到页面,在mounted中可以获得真实的DOM节点,并可以对其进行操作。我们经常会在vue中使用jQuery插件,jQuery操作的是真实的DOM,所以插件的初始化应该在mounted中进行。

3. beforeUpdate 和 updated

mounted之后,页面就展示出来了。由于Vue是数据驱动,当我们进行的操作更改了data中的值,页面DOM也会发生响应的变化。如果想要在update过程中进行一些操作,就要用到beforeUpdate和updated。

```html
<body>
    <div id="app">
        
    </div>
</body>
<script src='./vue.min.js'></script>
<script>
    new Vue({
        el: '#app',
        data:{
            msg: 'hello Vue',
            count: 10,
        },
        template:  '<div><span>{{msg}}</span><input type="text" v-model="msg"> <span>{{count}}</span></div>',
        beforeUpdate() {
            this.count = 100;
            console.log(this.$el.innerHTML);
            // <span>hello Vue</span><input type="text"> <span>10</span>
            // <span>hello Vu</span><input type="text"> <span>10</span>
        },
        updated() {
            console.log(this.$el.innerHTML);
            // <span>hello Vu</span><input type="text"> <span>100</span>
        }
    })
</script>
...
当我们通过input改变msg来触发update过程。并且在beforeUpdate中进一步更改了count的值。这样beforeUpdate运行了两次,而在这个函数中虚拟DOM还没有开始渲染,所以即使改变count值为100,输出依然时旧值10。updated在组件DOM更新完成时触发。如果你的操作依赖于更新后的DOM,就应该在此时进行。但是要注意尽量不要在updated中再次改变data中的值,这会再次触发更新操作,比较容易导致死循环。

4. beforeDestroy 和 destroyed

当我们不再需要一个组件,可以执行$destroy销毁它。在beforeDestroy中,组件一切都是正常的,可以进行最后的操作。下面是Vue源码中调用beforeDestroy和destoryed的间隔中,执行的操作。

callHook(vm, 'beforeDestroy');
vm._isBeingDestroyed = true;
// remove self from parent
var parent = vm.$parent;
if (parent && !parent._isBeingDestroyed && !vm.$options.abstract) {
  remove(parent.$children, vm);
}
// teardown watchers
if (vm._watcher) {
  vm._watcher.teardown();
}
var i = vm._watchers.length;
while (i--) {
  vm._watchers[i].teardown();
}
// remove reference from data ob
// frozen object may not have observer.
if (vm._data.__ob__) {
  vm._data.__ob__.vmCount--;
}
// call the last hook...
vm._isDestroyed = true;
// invoke destroy hooks on current rendered tree
vm.__patch__(vm._vnode, null);
// fire destroyed hook
callHook(vm, 'destroyed');

从源码中的注释中了解到,销毁操作包括一下事情的处理:

1. remove self from parent (从父组件中移除)
2. teardown watchers (移除watchers)
3. remove reference from data observer (从observer中移除引用)
4. invoke destroy hooks on current rendered tree (处理DOM tree)
5. fire destroyed hook (触发destroyed)

至此,一个组件的生命周期就算结束了。

总结:

通过以上的分析,对一个Vue实例的生命周期便有了一个清晰的认识。从实例化开始(beoforeCreate)到销毁(destroyed),以及各个时期可以对哪些对象进行操作。最后附上官网的生命周期图示,相信阅读完文章,再看此图,会获得更好的理解

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,012评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,628评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,653评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,485评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,574评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,590评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,596评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,340评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,794评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,102评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,276评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,940评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,583评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,201评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,441评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,173评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,136评论 2 352

推荐阅读更多精彩内容