Contents

Vue-4逻辑复用

本系列是作者在跟着Vue官网学习时做的笔记,可能并不详尽,读者可以到官网中查看完整内容。本文只讲解带有<script setup>组合式API。

组合式函数

利用 Vue 的组合式 API 来封装和复用有状态逻辑的函数

鼠标跟踪器示例

见官网

异步状态示例

见官网

约定和最佳实践

命名:驼峰命名法命名,并以“use”作为开头

输入参数:unref()兼容ref

1
2
3
4
5
6
7
import { unref } from 'vue'

function useFeature(maybeRef) {
  // 若 maybeRef 确实是一个 ref,它的 .value 会被返回
  // 否则,maybeRef 会被原样返回
  const value = unref(maybeRef)
}

返回值:返回一个包含多个 ref 的非响应式对象,其在组件中结构后保持响应性

副作用:组合式函数中添加 DOM 事件监听器或者请求数据,注意2点

  1. 确保在组件挂载后才调用的生命周期钩子中执行 DOM 相关的副作用,例如:onMounted(),确保能访问到 DOM
  2. 确保在 onUnmounted() 时清理副作用

使用限制:组合式函数在 <script setup>应始终被同步地调用,以确定当前正在被执行的到底是哪个组件实例,从而:

  1. 将生命周期钩子注册到该组件实例上
  2. 将计算属性和监听器注册到该组件实例上,以便在该组件被卸载时停止监听,避免内存泄漏。

通过抽取组合式函数改善代码结构

抽取组合式函数不仅是为了复用,也是为了代码组织。

自定义指令

介绍

<script setup> 中,任何以 v 开头的驼峰式命名的变量都可以被用作一个自定义指令,模板中使用短横线连接

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<script setup>
// 在模板中启用 v-focus
const vFocus = {
  mounted: (el) => el.focus()
}
</script>

<template>
  <input v-focus />
</template>

指令钩子

一个指令的定义对象可以提供几种钩子函数 (都是可选的):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
const myDirective = {
  // 在绑定元素的 attribute 前
  // 或事件监听器应用前调用
  created(el, binding, vnode, prevVnode) {
    // 下面会介绍各个参数的细节
  },
  // 在元素被插入到 DOM 前调用
  beforeMount(el, binding, vnode, prevVnode) {},
  // 在绑定元素的父组件
  // 及他自己的所有子节点都挂载完成后调用
  mounted(el, binding, vnode, prevVnode) {},
  // 绑定元素的父组件更新前调用
  beforeUpdate(el, binding, vnode, prevVnode) {},
  // 在绑定元素的父组件
  // 及他自己的所有子节点都更新后调用
  updated(el, binding, vnode, prevVnode) {},
  // 绑定元素的父组件卸载前调用
  beforeUnmount(el, binding, vnode, prevVnode) {},
  // 绑定元素的父组件卸载后调用
  unmounted(el, binding, vnode, prevVnode) {}
}

钩子参数

  • el:指令绑定到的元素。这可以用于直接操作 DOM。
  • binding:一个对象,包含以下属性。
    • value:传递给指令的值
    • oldValue:之前的值
    • arg:传递给指令的参数
    • modifiers:一个包含修饰符的对象
    • instance:使用该指令的组件实例
    • dir:指令的定义对象
  • vnode:代表绑定元素的底层 VNode
  • prevNode:之前的渲染中代表指令所绑定元素的 VNode

自定义指令的参数也可以是动态的

1
<div v-example:[arg]="value"></div>

简化形式

仅仅需要在 mounted 和 updated 上实现相同的行为

1
2
3
4
app.directive('color', (el, binding) => {
  // 这会在 `mounted` 和 `updated` 时都调用
  el.style.color = binding.value
})

对象字面量

1
<div v-demo="{ color: 'white', text: 'hello!' }"></div>
1
2
3
4
app.directive('demo', (el, binding) => {
  console.log(binding.value.color) // => "white"
  console.log(binding.value.text) // => "hello!"
})

在组件上使用

子组件中该指令和透传 attributes 类似。

指令不能通过 v-bind="$attrs" 来传递给一个不同的元素

不推荐在组件上使用自定义指令

插件

介绍

1
2
3
4
5
6
7
import { createApp } from 'vue'

const app = createApp({})

app.use(myPlugin, {
  /* 可选的选项 */
})
1
2
3
4
5
const myPlugin = {
  install(app, options) {
    // 配置此应用
  }
}

常见用法:

  1. 通过 app.component() 和 app.directive() 注册一到多个全局组件或自定义指令
  2. 通过 app.provide() 使一个资源可被注入进整个应用
  3. 向 app.config.globalProperties 中添加一些全局实例属性或方法
  4. 一个可能上述三种都包含了的功能库 (例如 vue-router)

编写一个插件

见官网

 |