面试时这样回答Vue生命周期,面试官说:你明天直接来上班!!!

面试

面试前端时,我们经常会被问到:你能讲一下vue的生命周期吗?

你可能会这么说:vue的生命周期有beforeCreate、created、beforeMount、mounted......

面试官可能会告诉你:可以了,回去等面试结果通知吧!!!

如果这时你还能讲一讲vue生命周期的执行原理,这岂不是能在面试中有所加分,不然,你拿什么与别人与众不同

要想深入了解vue的生命周期,首先让我们看到vue源码

Vue生命周期源码解析

callHook函数

在vue源码lifecycle.ts文件下有这么一个方法:

scss 复制代码
//lifecycle.ts
export function callHook(
  vm: Component,
  hook: string,
  args?: any[],
  setContext = true
) {
  // #7573 disable dep collection when invoking lifecycle hooks
  pushTarget()
  const prev = currentInstance
  setContext && setCurrentInstance(vm)
  const handlers = vm.$options[hook]
  const info = `${hook} hook`
  if (handlers) {
    for (let i = 0, j = handlers.length; i < j; i++) {
      invokeWithErrorHandling(handlers[i], vm, args || null, vm, info)
    }
  }
  if (vm._hasHookEvent) {
    vm.$emit('hook:' + hook)
  }
  setContext && setCurrentInstance(prev)
  popTarget()
}

这个方法被多处引入使用

_init方法中:

mountComponent方法中:

callUpdatedHooks方法中:

$destroy方法中:

其实这些callHook方法都是在执行相应的生命周期钩子函数,即:执行所提供的生命周期回调函数

callHook函数形参:

vm:Component(当前组件实例对象)

hook:string(生命周期名,如:"beforeCreate","created","beforeMount","mounted"......)

args:any[](执行生命周期钩子函数时,传递的参数)

setContext:Boolean(默认为true,为真时设置currentInstance为vm实例对象,为假时不进行此操作)

callHook函数是如何获取并执行生命周期钩子函数的?

回到callHook函数中,const handlers = vm.$options[hook]handlers变量(存储着对应生命周期钩子函数的数组)

继续往下

typescript 复制代码
//lifecycle.ts
//callHook函数中
if (handlers) {
  for (let i = 0, j = handlers.length; i < j; i++) {
    invokeWithErrorHandling(handlers[i], vm, args || null, vm, info)
  }
}
​
​
//error.ts
export function invokeWithErrorHandling(
  handler: Function,
  context: any,
  args: null | any[],
  vm: any,
  info: string
) {
  let res
  try {
    res = args ? handler.apply(context, args) : handler.call(context)
    if (res && !res._isVue && isPromise(res) && !(res as any)._handled) {
      res.catch(e => handleError(e, vm, info + ` (Promise/async)`))
      // issue #9511
      // avoid catch triggering multiple times when nested calls
      ;(res as any)._handled = true
    }
  } catch (e: any) {
    handleError(e, vm, info)
  }
  return res
}

callHook 函数中遍历handlers (生命周期钩子函数数组),遍历至每一项时会执行函数:invokeWithErrorHandling(handlers[i], vm, args || null, vm, info)

handlers[i]为生命周期钩子函数

vm为当前组件实例对象

args为传递给钩子函数的参数

info为string:"生命周期名 hook"

然后,通过invokeWithErrorHandling 函数中res = args ? handler.apply(context, args) : handler.call(context) 执行相应生命周期钩子函数

handlers生命周期钩子函数为何是数组?

handlers中包含通过minxin混入的生命周期钩子函数和组件的生命周期钩子函数,所以它是一个数组 ,handlers[]:Function

vm.$options[hook]是在何时初始化生命周期钩子函数的?

_init函数中:

swift 复制代码
//init.ts
//Vue.prototype._init中
   if (options && options._isComponent) {
      // optimize internal component instantiation
      // since dynamic options merging is pretty slow, and none of the
      // internal component options needs special treatment.
      initInternalComponent(vm, options as any)
    } else {
      vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor as any),
        options || {},
        vm
      )
    }

如果当前初始化是new Vue实例,会执行*vm. <math xmlns="http://www.w3.org/1998/Math/MathML"> o p t i o n s = m e r g e O p t i o n s ( r e s o l v e C o n s t r u c t o r O p t i o n s ( v m . c o n s t r u c t o r a s a n y ) , o p t i o n s ∣ ∣ , v m ) ∗ ,并且生命周期钩子函数数组挂载在 v m . options = mergeOptions(resolveConstructorOptions(vm.constructor as any),options || {},vm)* ,并且生命周期钩子函数数组挂载在vm. </math>options=mergeOptions(resolveConstructorOptions(vm.constructorasany),options∣∣,vm)∗,并且生命周期钩子函数数组挂载在vm.options上

如果是子组件初始化,会执行initInternalComponent(vm, options as any) ,并且生命周期钩子函数数组会挂载在vm.$options原型链上

vue组件@hook:xxx事件

callHook 函数在执行完生命周期钩子函数(invokeWithErrorHandling)后会执行hook:xxx事件

bash 复制代码
//lifecycle.ts
//callHook函数中
if (vm._hasHookEvent) {
    vm.$emit('hook:' + hook)
}

例如我们要在父组件中监听子组件mounted钩子函数执行完,我们可以这样做:

1、子组件与父组件通过on与emit进行发布订阅

2、在子组件上注册hook:xxx事件:<compontent @hook:mounted="action" />,action事件会在执行完mounted生命周期钩子函数后被调用

如果觉得内容对你有帮助或者有所成长,麻烦请点个小小的赞加收藏,谢谢。^o^

相关推荐
PleaSure乐事1 小时前
JS/JSP/JSX的区别与关联
前端·javascript·react.js·前端框架·jsp·jsx
nothing_more_than7 小时前
draggable的el-dialog实现对话框标题可以选择
javascript·vue.js·element-plus
小镇程序员8 小时前
vue2 src自定义事件
前端·javascript·vue.js
炒毛豆8 小时前
vue3+echarts+ant design vue实现进度环形图
javascript·vue.js·echarts
别拿曾经看以后~10 小时前
原生Android调用uniapp项目中的方法
android·vue.js·uni-app
GISer_Jing11 小时前
从0开始分享一个React项目:React-ant-admin
前端·react.js·前端框架
川石教育11 小时前
Vue前端开发子组件向父组件传参
前端·vue.js·前端开发·vue前端开发·vue组件传参
Embrace92411 小时前
为什么 Vue2会出现数据更新视图不更新 Vue3不会出现
javascript·vue.js·ecmascript
qq_4156281711 小时前
bpmn.js显示流程图
javascript·vue.js·流程图
GISer_Jing11 小时前
Vue前端进阶面试题目(二)
前端·vue.js·面试