WJ-Yuan / Notes

My Tech Notes
https://wj-yuan.github.io/Notes/
0 stars 0 forks source link

[Note] element-plus 源码阅读笔记 - hooks #9

Open WJ-Yuan opened 1 year ago

WJ-Yuan commented 1 year ago

hooks

useAttrs

这个 hook 用于传递全局属性。 fromPairs 其实可以用 object.fromEntries 代替。是 vue 中 useAttrs 的实现。

useCursor

TODO: 这个 hook 没太看懂,主要对 setSelectionRange 这个 api 不太熟。

useDeprecated

这个 hook 用来检测某个 API、属性、事件或者插槽当前版本是否已经不适用并发出警告。

useDraggable

这个 hook 用来处理元素的拖拽。参数 1 是目标元素 ref 值,参数 2 是被拖拽的元素 ref 值,参数 3 是是否可拖拽。主要是用在 message-box 和 modal 里来处理整个 modal 或者 message-box 的拖拽。

TODO: 为何不直接使用原生拖拽事件?

useFocus

这个 hook 是使页面 focus 到当前元素,传入的必须是个 ref 响应对象,我们可以利用它返回的 focus 函数轻松调用。

useForwardRef

这个 hook 可能是类似 react 中 forwardRef 的作用。

useId

随机生成 id,没看懂有什么作用。

useLocale

这个 hook 很明显是用来处理 i18n 的,是一个简易版本的 vue-i18n 实现,实际项目中我们一般使用 vue-i18n 处理国际化。 但是其实现思路值得借鉴。具体代码如下:

import { computed, inject, isRef, ref, unref } from 'vue'
import { get } from 'lodash-unified'
import English from '@element-plus/locale/lang/en'

import type { MaybeRef } from '@vueuse/core'
import type { InjectionKey, Ref } from 'vue'
import type { Language } from '@element-plus/locale'

export type TranslatorOption = Record<string, string | number>
export type Translator = (path: string, option?: TranslatorOption) => string
export type LocaleContext = {
  locale: Ref<Language>
  lang: Ref<string>
  t: Translator
}

export const buildTranslator =
  (locale: MaybeRef<Language>): Translator =>
  (path, option) =>
    translate(path, option, unref(locale))

export const translate = (
  path: string,
  option: undefined | TranslatorOption,
  locale: Language
): string =>
  (get(locale, path, path) as string).replace(
    /\{(\w+)\}/g,
    (_, key) => `${option?.[key] ?? `{${key}}`}`
  )

export const buildLocaleContext = (
  locale: MaybeRef<Language>
): LocaleContext => {
  const lang = computed(() => unref(locale).name)
  const localeRef = isRef(locale) ? locale : ref(locale)
  return {
    lang,
    locale: localeRef,
    t: buildTranslator(locale),
  }
}

export const localeContextKey: InjectionKey<Ref<Language | undefined>> =
  Symbol('localeContextKey')

export const useLocale = (localeOverrides?: Ref<Language | undefined>) => {
  const locale = localeOverrides || inject(localeContextKey, ref())!
  return buildLocaleContext(computed(() => locale.value || English))

useModal

这个 hook 是用于处理 modal 的显隐,并且在点击 ESC 键时,自动关闭顶层 modal。个人觉得实用价值不太高,但关闭顶层 modal 的思路值得学习下。

useProp

这个 hook 的作用是提取当前组件的 prop 的某个属性作为 computed 对象。 主要涉及到 getCurrentInstance 这个 API ,个人感觉这个 hook 没有太大的使用价值,因为如果是需要解构的场景,完全可以使用 toReftoRefs 函数来替代。

useGlobalSize

这个 hook 用来在当前组件中获取全局 size 参数且只读。主要的知识点是 vue 核心库中 inject 的使用。

useTeleport

这个 hook 的作用在客户端的组件中轻松将 vnode 的内容添加到 Teleport 中,轻松创建模态框等,并且在当前组件卸载时自动销毁隐藏元素。如果在服务端不会实际渲染。 主要涉及到 vue 的 Teleport 组件 以及 h 函数 以及 vueuse 中的 isClient 方法。

isClient 的实现非常简单:

export const isClient = typeof window !== 'undefined';

useThrottleRender

这个 hook 用于骨架屏渲染延迟。

useTimeout

这个 hook 用于在 window 中安全地注册延时函数,并在作用域销毁的同时安全地销毁 setTimeout,以避免作用域销毁时用户忘记清除宏任务造成内存溢出。 这个 hook 的核心使用了 window.setTimeout@vueuse/core 中的 tryOnScopeDispose 函数。实际上 tryOnScopeDispose 只是对 vue 核心库中的 getCurrentScopeonScopeDispose 两个 API 的简单封装。