前端工程化的最终目的都是为了能够更好地维护代码。代码复用是提升效率和可维护性的利器。
vue 中针对不同场景和业务情况,提供了各种方式。全面了解这些内容,可以在开发过程中让你得心应手!
方式 | 建议 |
---|---|
组件 | 主要的构建模块 |
组合式函数 | 侧重于有状态的逻辑 |
自定义指令 | 重用涉及普通元素的底层 DOM 访问的逻辑 |
插件 | 添加全局功能的工具代码 |
组件
组件允许我们将 UI 划分为独立的、可重用的部分,并且可以对每个部分进行单独的思考。
具体细则内容,可查看上篇文章:掌握这些容易被忽略的Vue组件细节,提升开发效率,事半功倍!
组合式函数
利用 Vue 的组合式 API 来封装和复用有状态逻辑的函数
import { ref, isRef, unref, watchEffect } from 'vue'
export function useFetch(url) {
const data = ref(null)
const error = ref(null)
function doFetch() {
// 在请求之前重设状态...
data.value = null
error.value = null
// unref() 解包可能为 ref 的值
fetch(unref(url))
.then((res) => res.json())
.then((json) => (data.value = json))
.catch((err) => (error.value = err))
}
if (isRef(url)) {
// 若输入的 URL 是一个 ref,那么启动一个响应式的请求
watchEffect(doFetch)
} else {
// 否则只请求一次
// 避免监听器的额外开销
doFetch()
}
return { data, error }
}
useFetch
:组合式函数约定用驼峰命名法命名,并以“use”作为开头;watchEffect(doFetch)
:兼容ref
,通过watchEffect
正确的追踪,高效又省事;unref(url)
:unref()
解包可能为 ref 的值,如果是 ref 返回.value
会被返回,否则会被原样返回;return { data, error }
:返回一个包含多个 ref 的普通的非响应式对象,这样该对象在组件中被解构为 ref 之后仍可以保持响应性;- 组合式函数在
<script setup>
或setup()
钩子中,应始终被同步地调用 – 为了让 Vue 能够确定当前正在被执行的到底是哪个组件实例。==><script setup>
是唯一在调用 await 之后仍可调用组合式函数的地方。
自定义指令
<script setup>
// 在模板中启用 v-focus
const vFocus = {
mounted: (el) => el.focus()
}
</script>
<template>
<input v-focus />
</template>
- 只有当所需功能只能通过直接的 DOM 操作来实现时,才应该使用自定义指令。其他情况下应该尽可能地使用
v-bind
这样的内置指令来声明式地使用模板,这样更高效,也对服务端渲染更友好。 - 当在组件上使用自定义指令时,它会始终应用于组件的根节点,和透传 attributes 类似。==> 需要注意的是组件可能含有多个根节点。当应用到一个多根组件时,指令将会被忽略且抛出一个警告。
[Vue warn]: Runtime directive used on component with non-element root node. The directives will not function as intended.
app.directive('color', (el, binding) => {
// 这会在 `mounted` 和 `updated` 时都调用
el.style.color = binding.value
})
以上,仅在 mounted
和 updated
上实现相同的行为,除此之外其他钩子不执行。
插件
为 Vue 添加全局功能的工具代码
<h1>{{ $translate('greetings.hello') }}</h1>
<script setup>
import { inject } from 'vue'
const i18n = inject('i18n')
console.log(i18n.greetings.hello)
</script>
// plugins/i18n.js
export default {
install: (app, options) => {
// 注入一个全局可用的 $translate() 方法
app.config.globalProperties.$translate = (key) => {
// 获取 `options` 对象的深层属性
// 使用 `key` 作为索引
return key.split('.').reduce((o, i) => {
if (o) return o[i]
}, options)
}
app.provide('i18n', options)
}
}
// options 注册是添加
app.use(i18nPlugin, {
greetings: {
hello: 'Bonjour!'
}
})
app.config.globalProperties
将$translate
其添加到全局,任意模板中可调用;- 通过
Provide/Inject
,options
参数提供给整个应用,让任何组件都能使用这个翻译字典对象