美文网首页
vue的生命周期

vue的生命周期

作者: nice生活 | 来源:发表于2019-08-23 13:48 被阅读0次

生命周期就是从Vue实例创建、运行、到销毁的一个过程,在vue中提供了生命周期钩子的函数,可以在不同生命周期阶段添加自己的代码。

实例生命周期钩子

lifecycle.png

上面就是官网的图片,可以看到vue有beforeCreate,Created...等8个生命周期钩子,那么在执行到这些操作时,vue做了什么事情,我们可以从源码上看

    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

在执行beforeCreate前有initLifecycle,initEvents,initRender三个函数

initLifecycle

export function initLifecycle (vm: Component) {
  const options = vm.$options
  // locate first non-abstract parent
  let parent = options.parent
  if (parent && !options.abstract) {
    while (parent.$options.abstract && parent.$parent) {
      parent = parent.$parent
    }
    parent.$children.push(vm)
  }
  vm.$parent = parent
  vm.$root = parent ? parent.$root : vm
  vm.$children = []
  vm.$refs = {}
  vm._watcher = null
  vm._inactive = null
  vm._directInactive = false
  vm._isMounted = false
  vm._isDestroyed = false
  vm._isBeingDestroyed = false
}

基本上就是一下vm实例属性的初始化

initEvents

export function initEvents (vm: Component) {
  vm._events = Object.create(null)//创建一个空对象,vm._events存放组件父组件绑定在当前组件上的事件
  vm._hasHookEvent = false //表示的是父组件有没有直接绑定钩子函数在当前组件上
  const listeners = vm.$options._parentListeners
  if (listeners) {
    updateComponentListeners(vm, listeners)//更新事件
  }
}

主要就是事件的注册

initRender

export function initRender (vm: Component) {
  vm._vnode = null // the root of the child tree
  vm._staticTrees = null // v-once cached trees
  const options = vm.$options
  const parentVnode = vm.$vnode = options._parentVnode // the placeholder node in parent tree
  const renderContext = parentVnode && parentVnode.context
  vm.$slots = resolveSlots(options._renderChildren, renderContext)
  vm.$scopedSlots = emptyObject
  // bind the createElement fn to this instance
  // so that we get proper render context inside it.
  // args order: tag, data, children, normalizationType, alwaysNormalize
  // internal version is used by render functions compiled from templates
  vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)
  // normalization is always applied for the public version, used in
  // user-written render functions.
  vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)

  // $attrs & $listeners are exposed for easier HOC creation.
  // they need to be reactive so that HOCs using them are always updated
  const parentData = parentVnode && parentVnode.data

  /* istanbul ignore else */
  if (process.env.NODE_ENV !== 'production') {
    defineReactive(vm, '$attrs', parentData && parentData.attrs || emptyObject, () => {
      !isUpdatingChildComponent && warn(`$attrs is readonly.`, vm)
    }, true)
    defineReactive(vm, '$listeners', options._parentListeners || emptyObject, () => {
      !isUpdatingChildComponent && warn(`$listeners is readonly.`, vm)
    }, true)
  } else {
    defineReactive(vm, '$attrs', parentData && parentData.attrs || emptyObject, null, true)
    defineReactive(vm, '$listeners', options._parentListeners || emptyObject, null, true)
  }
}

貌似是创建虚拟节点的,=-=

可以看出在执行beforeCreate前vue只是做一些属性,事件的初始化,而data,props并没有做初始化,故而在这里是不能用this.data的

initInjections

export function initInjections (vm: Component) {
  const result = resolveInject(vm.$options.inject, vm)
  if (result) {
    toggleObserving(false)  //禁用观察
    Object.keys(result).forEach(key => {
      /* istanbul ignore else */
      if (process.env.NODE_ENV !== 'production') {
        defineReactive(vm, key, result[key], () => {
          warn(
            `Avoid mutating an injected value directly since the changes will be ` +
            `overwritten whenever the provided component re-renders. ` +
            `injection being mutated: "${key}"`,
            vm
          )
        })
      } else {
        defineReactive(vm, key, result[key])  // getter setter
      }
    })
    toggleObserving(true)
  }
}

初始化 initInjections inject

initState

export function initState (vm: Component) {
  vm._watchers = []
  const opts = vm.$options
  if (opts.props) initProps(vm, opts.props) //初始化props
  if (opts.methods) initMethods(vm, opts.methods) // 初始化methods
  if (opts.data) {                            
    initData(vm) // 
  } else {
    observe(vm._data = {}, true /* asRootData */)
  }
  if (opts.computed) initComputed(vm, opts.computed) //computed初始化
  if (opts.watch && opts.watch !== nativeWatch) {
    initWatch(vm, opts.watch)   // watch初始化
  }
}

主要props,methods, data, computed,watch初始化

initProvide

export function initProvide (vm: Component) {
  const provide = vm.$options.provide
  if (provide) {
    vm._provided = typeof provide === 'function'
      ? provide.call(vm)
      : provide
  }
}

provide

可以看出在created可以获取props,methods, data,computed,watch

export function mountComponent (
  vm: Component,
  el: ?Element,
  hydrating?: boolean
): Component {
  vm.$el = el
  //略
  callHook(vm, 'beforeMount')

  let updateComponent
  /* istanbul ignore if */
  if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
   //略
    }
  } else {
    updateComponent = () => {
      vm._update(vm._render(), hydrating) //挂载节点
    }
  }
  new Watcher(vm, updateComponent, noop, {
    before () {
      if (vm._isMounted && !vm._isDestroyed) {
        callHook(vm, 'beforeUpdate')
      }
    }
  }, true /* isRenderWatcher */)
  hydrating = false
  if (vm.$vnode == null) {
    vm._isMounted = true
    callHook(vm, 'mounted')
  }
  return vm
}

可以知道在beforeMount里真实的dom还没挂载所以不能用this.$refs.xx获取dom,并且是最后一次改this.data而不触发updated的生命周期,除此外beforeMount 到 mounted之间会触发子组件的生命周期。

test

//main.vue
<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <HelloWorld :msg="msg" ref="h"/>
  </div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
  name: 'app',
  components: {
    HelloWorld
  },
  data() {
     return{
         msg:'Welcome'
     } 
  },
  beforeCreate() {
      console.log(0,this.msg)
  },
  created() {
      console.log(1,this.msg)
  },
  beforeMount() {
      this.msg = 'ok'
      console.log(3,this.$ref.h)
  },
  mounted() {
      this.msg = 'ff'
      console.log(4,this.$ref.h)
  }
}
</script>
//HelloWorld.vue
<template>
  <div class="hello">
      {{test}}
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  computed:{
       test(){
         console.log(this.msg)
         return this.msg
    }
  },
  beforeCreate() {
      console.log(2,'child created')
  }
}
</script>

结果

QQ图片20190823134715.png

相关文章

  • vue生命周期

    一 vue生命周期 Vue的生命周期:就是vue实例从创建到销毁的全过程 二 vue生命周期钩子 vue生命周期...

  • vue生命周期

    vue生命周期详: vue生命周期详解图: vue生命周期详解代码展示:

  • Vue生命周期

    Vue生命周期详解 一、Vue生命周期 与 作用 (生命周期钩子就是生命周期函数) (1)Vue生命周期:每个Vu...

  • vue3较vue2的特别之处 - 生命周期

    vue2 生命周期 vue3 生命周期 将 Vue2 的生命周期钩子代码更新到 Vue3 参考地址:https:/...

  • 前端之路-VUE面试题

    vue生命周期面试题vue 生命周期是什么? Vue 实例从创建到销毁的过程,就是生命周期 beforeCreat...

  • Vue.js入门(二):生命周期

    1 生命周期 Vue生命周期是Vue实例从创建到销毁的过程,就是生命周期。在Vue实例的生命周期过程中会运行生命周...

  • vue生命周期

    vue里的生命周期是什么? vue实例从创建到销毁的过程称之为vue的生命周期 vue的生命周期各阶段都做了什么?...

  • Vue 生命周期

    vue里的生命周期是什么? vue实例从创建到销毁的过程称之为vue的生命周期 vue的生命周期各阶段都做了什么?...

  • vue学习记录

    vue全家桶 vue生命周期 生命周期的理解 新建项目 ①:cnpm install vue-cli -g (全...

  • vue生命周期

    vue1--》 一 vue的生命周期如下图所示 二 vue生命周期的例子 注意触发vue的created事件以后,...

网友评论

      本文标题:vue的生命周期

      本文链接:https://www.haomeiwen.com/subject/mkvasctx.html