feng xiaohan

组件逻辑复用

单文件组件

.vue 结尾的文件,在 <script setup> 中定义组件逻辑,在 <template> 中定义组件模板。可复用组件及其对应逻辑。用于构建模块

组合式函数

约定俗成以 use 开头的函数,他可以将公共任务逻辑(有状态的逻辑)抽离出来,以函数的形式复用;在 use 函数内部同样可以使用 Vue 的钩子函数和语法,执行顺序在使用组件前。

官网的例子是追踪鼠标变换。在实际架构中,会创建一个 hook 文件夹,根据 use 函数的功能,可分为 core、event、setting、web 等文件夹,分别存放对应的 hook 函数

  • core:存放核心通用逻辑,比如 useAtrrs hook 用于组合属性或类名前缀等。
  • setting:存放相关配置,比如一些全局的属性(后台应用的菜单详情配置),颜色十六进制转换,不同状态映射关系,还可以将 store 存储的信息用 computed 进行 ref 封装。
  • event:存放事件相关的逻辑,比如 useScroll 滚动事件处理,在里面可以配置防抖节流操作。
  • web:存放与 web 相关的逻辑,比如 useWebSocket 封装 websocket,useDesign 设置不同类名前缀,use18n 配置国际化等。
  • component:…

组合式函数传参

组合式函数的执行顺序在当前组件之前,对于需要在当前组件内动态传参赋值时,可以在组合式函数内部使用 toValue()watchEffect()来转换和监听

也就是接收一个 ref 或 getter 函数,而 toValue() 可以将 ref 或 getter 规范化为值

最佳实践

  • 命名:use 开头的驼峰命名法
  • 动态输入参数:watch + ref/geeter 或 **watchEffect + toValue()**;
  • 返回值:非响应式对象,该对象中包含多个 ref 值
  • 副作用:确保在组件卸载的生命周期中清理副作用,也可以封装专门的组合式函数来处理注册和清除;

    在组合式函数中添加 DOM 实践监听器或请求数据等操作。

  • 使用限制:只能<script setup> 或 setup() 钩子中被同步调用。某些情况下也可以像onMounted这样的生命周期钩子中调用。

    这些限制是为了 Vue 能确定当前活跃的组件实例的上下文,用于注册生命周期钩子,添加计算属性和监听器,以便于组件卸载时停止监听,避免内存泄漏。

  • 适当抽取组合是函数改善代码结构:组合式 API 可以更灵活的将逻辑部分抽离。
  • 选项式 API:组合式函数必须在 setup() 中调用,且必须在 setup() 中返回以便暴露给模板;

与 Mixin 的对比

Mixin 主要是针对 Vue2,相比组合式函数,它主要的问题有:

  • 不清晰的数据来源;
  • 命名空间冲突;
  • 隐式的跨 mixin 交流;

与无渲染组件的对比

一些组件可能只包括了逻辑而不需要自己渲染内容,视图输出通过作用域插槽全权交给了消费者组件。对比它来说组合式函数的优势是:

  • 不会产生额外的组件开销

所以在纯逻辑复用时还是该使用组合式函数,

自定义指令

注册自定义指令,主要是用于重用涉及普通元素的底层 DOM 访问逻辑

<script setup>,任何以* v 开头的驼峰式命名的变量都可以当作自定义指令都可以在模板中使用,并且不需要导入。

自定义指令对象中提供几种生命周期钩子函数,钩子函数的默认参数有:

  • el:DOM 元素;
  • binding:对象,包含以下属性:
    • value:传递给指令的值(value);
    • oldValue:之前的值,仅在 beforeUpdateupdated 钩子中可用;
    • arg:传递给指令的参数(:后的参数);
    • modifiers:修饰符对象(.后的参数);
    • instance:组件实例(谁用是谁的);
    • dir:指令的定义对象;
  • vnode:底层 vnode;
  • prevNode:之前的渲染中指令绑定的 vnode,仅在 beforeUpdateupdated 钩子中可用;

当需要操纵 DOM 时才使用,一般将自定义指令放在 directives 文件夹下,在挂载 app 前就将所有的自定义指令注册到了全局(setupGlobalDirectives)

使用方式

  1. <script setup> 中:
<script setup>
const vHighlight = {
  mounted: (el) => {
    el.classList.add("is-highlight");
  },
};
</script>

<template>
  <p v-highlight>This sentence is important!</p>
</template>
  1. setup() 函数中:
export default {
  setup() {},
  directives: {
    // 在模板中启用 v-highlight
    highlight: {
      /* ... */
    },
  },
};
  1. 全局注册:
const app = createApp({});
app.directive("highlight", {
  /* ... */
});

其他

  • 动态参数:自定义指令的参数可以是动态的,他会基于这个动态参数响应式地更新;
  • 简化形式:可进行简化操作,在不指定钩子函数时,默认的回调函数会在 mountedupdated都执行
  • 对象字面量:可向自定义指令传递多个值,以对象字面量形式传递,在 bingding.value 中接收;
  • 组件上使用(*):会始终应用于组件的根元素(和透传 attributes 类似),对于多根组件会忽略该指令;

    不推荐在组件上使用。

插件

为 Vue 添加全局功能的工具代码。一个插件可以是一个拥有 install() 方法的对象,也可以直接是一个安装函数本身,使用 app.use() 安装。

应用:

  • 全局注册组件、指令;

    组件库。

  • 通过 app.provide() 向应用注入整个资源;
  • 通过 app.config.globalProperties 添加全局实例属性或方法;