Интерпретация исходного кода Vue (7) — Hook Event

JavaScript Vue.js
Интерпретация исходного кода Vue (7) — Hook Event

предисловие

Hook Event(Hook event) Я считаю, что многие разработчики Vue никогда не использовали или даже не слышали о нем, ведь в официальной документации Vue он не упоминается.

Vue предоставляет разработчикам некоторые функции-ловушки жизненного цикла для добавления дополнительной логики обработки в определенные логические точки, например: на этапе монтажа компонента.beforeMountиmountedДва хука жизненного цикла, позволяющие разработчикам выполнять дополнительную логическую обработку на этапе монтирования компонента, например подготовку данных для рендеринга компонента.

Тогда это Hook Event — событие ловушки, которое также означает ловушку, какое отношение оно имеет к функции ловушки жизненного цикла Vue? Какая от этого польза? Именно на этот вопрос и призвана ответить данная статья.

Цель

  • Понять, что такое Hook Event? понять вариант использования

  • Глубокое понимание принципа реализации Hook Event

Что такое хуковое событие?

Hook Event — это функция, реализованная пользовательскими событиями Vue в сочетании с хуками жизненного цикла для внедрения дополнительных методов жизненного цикла в компоненты извне компонента.

сцены, которые будут использоваться

Если предположить, что такой сторонний бизнес-компонент есть, то логика очень проста: в смонтированном жизненном цикле вызывается интерфейс для получения данных, а затем данные отрисовываются на странице.

<template>
  <div class="wrapper">
    <ul>
      <li v-for="item in arr" :key="JSON.stringify(item)">
        {{ item }}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      arr: []
    }
  },
  async mounted() {
    // 调用接口获取组件渲染的数据
    const { data: { data } } = await this.$axios.get('/api/getList')
    this.arr.push(...data)
  }
}
</script>

Потом я обнаружил, что в этом компоненте есть некоторые недочеты.Например самый простой, время ожидания интерфейса может быть долгим.Хочу выводить сообщение в консоль, когда смонтированный жизненный цикл начинает выполняться.loading ...Строка для улучшения взаимодействия с пользователем.

Как можно выполнить это требование?

Есть два пути: первый более хлопотный, модифицирующий исходный код, а второй гораздо проще, то есть представленное сегодня Hook Event, которое внедряет в компонент дополнительные методы жизненного цикла извне компонента.

<template>
  <div class="wrapper">
    <comp @hook:mounted="hookMounted" />
  </div>
</template>

<script>
// 这就是上面的那个第三方业务组件
import Comp from '@/components/Comp.vue'

export default {
  components: {
    Comp
  },
  methods: {
    hookMounted() {
      console.log('loading ...')
    }
  }
}
</script>

В это время, если вы снова обновите страницу, вы обнаружите, что когда бизнес-компонент запрашивает данные, он выводитloading ...нить.

эффект

Что делает Hook Event?

Дополнительные методы жизненного цикла могут быть введены в компоненты извне через Hook Events.

Принцип реализации

Зная сценарии использования и функции Hook Event, затем найдите принцип его реализации из исходного кода, чтобы «знать, что это такое и зачем это».

Как упоминалось ранее, Hook Event — это функция, реализованная пользовательскими событиями Vue в сочетании с функциями ловушек жизненного цикла, поэтому давайте посмотрим на код, связанный с жизненным циклом, например: мы знаем, что функции жизненного цикла Vue реализуются через вызовcallHookметод выполнения

callHook

/src/core/instance/lifecycle.js

/**
 * callHook(vm, 'mounted')
 * 执行实例指定的生命周期钩子函数
 * 如果实例设置有对应的 Hook Event,比如:<comp @hook:mounted="method" />,执行完生命周期函数之后,触发该事件的执行
 * @param {*} vm 组件实例
 * @param {*} hook 生命周期钩子函数
 */
export function callHook (vm: Component, hook: string) {
  // 在执行生命周期钩子函数期间禁止依赖收集
  // #7573 disable dep collection when invoking lifecycle hooks
  pushTarget()
  // 从实例配置对象中获取指定钩子函数,比如 mounted
  const handlers = vm.$options[hook]
  // mounted hook
  const info = `${hook} hook`
  if (handlers) {
    // 通过 invokeWithErrorHandler 执行生命周期钩子
    for (let i = 0, j = handlers.length; i < j; i++) {
      invokeWithErrorHandling(handlers[i], vm, null, vm, info)
    }
  }
  // Hook Event,如果设置了 Hook Event,比如 <comp @hook:mounted="method" />,则通过 $emit 触发该事件
  // vm._hasHookEvent 标识组件是否有 hook event,这是在 vm.$on 中处理组件自定义事件时设置的
  if (vm._hasHookEvent) {
    // vm.$emit('hook:mounted')
    vm.$emit('hook:' + hook)
  }
  // 关闭依赖收集
  popTarget()
}

invokeWithErrorHandling

/src/core/util/error.js

/**
 * 通用函数,执行指定函数 handler
 * 传递进来的函数会被用 try catch 包裹,进行异常捕获处理
 */
export function invokeWithErrorHandling (
  handler: Function,
  context: any,
  args: null | any[],
  vm: any,
  info: string
) {
  let res
  try {
    // 执行传递进来的函数 handler,并将执行结果返回
    res = args ? handler.apply(context, args) : handler.call(context)
    if (res && !res._isVue && isPromise(res) && !res._handled) {
      res.catch(e => handleError(e, vm, info + ` (Promise/async)`))
      // issue #9511
      // avoid catch triggering multiple times when nested calls
      res._handled = true
    }
  } catch (e) {
    handleError(e, vm, info)
  }
  return res
}

vm.$on

/src/core/instance/events.js

/**
 * 监听实例上的自定义事件,vm._event = { eventName: [fn1, ...], ... }
 * @param {*} event 单个的事件名称或者有多个事件名组成的数组
 * @param {*} fn 当 event 被触发时执行的回调函数
 * @returns 
 */
Vue.prototype.$on = function (event: string | Array<string>, fn: Function): Component {
  const vm: Component = this
  if (Array.isArray(event)) {
    // event 是有多个事件名组成的数组,则遍历这些事件,依次递归调用 $on
    for (let i = 0, l = event.length; i < l; i++) {
      vm.$on(event[i], fn)
    }
  } else {
    // 将注册的事件和回调以键值对的形式存储到 vm._event 对象中 vm._event = { eventName: [fn1, ...] }
    (vm._events[event] || (vm._events[event] = [])).push(fn)
    // hookEvent,提供从外部为组件实例注入声明周期方法的机会
    // 比如从组件外部为组件的 mounted 方法注入额外的逻辑
    // 该能力是结合 callhook 方法实现的
    if (hookRE.test(event)) {
      vm._hasHookEvent = true
    }
  }
  return vm
}

Суммировать

  • интервьюер спросил: Что такое Hook Event?

    отвечать:

    Hook Event — это функция, реализованная пользовательскими событиями Vue в сочетании с хуками жизненного цикла для внедрения дополнительных методов жизненного цикла в компоненты извне компонента.


  • интервьюер спросил: Реализовано ли Hook Event?

    отвечать:

    <comp @hook:lifecycleMethod="method" />
    
    • При обработке пользовательских событий компонента (vm.$on), если обнаружено, что компонентhook:xxсобытие форматирования (xx — функция жизненного цикла Vue), затемvm._hasHookEventустановлен вtrue, указывающее, что компонент имеет Hook Event

    • Когда срабатывает метод жизненного цикла компонента, внутренний проходcallHookметод для выполнения этих функций жизненного цикла после выполнения функции жизненного цикла, если она найденаvm._hasHookEventЕсли это правда, это означает, что текущий компонент имеет Hook Event.vm.$emit('hook:xx')Инициировать выполнение Hook Event

    Это принцип реализации Hook Event.

Сопутствующее видео

Интерпретация исходного кода Vue (7) — Hook Event

Поиск внимания

Приветствую всех, чтобы следовать за мнойСчет наггетсиСтанция Б, если контент полезен для вас, ставьте лайк, добавляйте в избранное + подписывайтесь

Ссылка на сайт

группа по обмену знаниями

Ссылка на сайт