本文来分享 25 个 Vue 开发必备的实用技巧!
使用 defineModel() 实现双向数据绑定
在 Vue 3.4 中,推荐使用 defineModel() 宏来实现双向数据绑定,这大大简化了代码。
<!-- 使用 defineModel 之前 -->
<script setup>
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
</script>
<template>
<input
:value="props.modelValue"
@input="emit('update:modelValue', $event.target.value)"
/>
</template>
<!-- 使用 defineModel 之后 -->
<script setup>
const model = defineModel();
</script>
<template>
<input v-model="model" />
</template>
避免滥用 ref()
在 Vue 中,不需要为每个变量都使用 ref(),只有在需要响应性时才使用。
<script setup>
// 不需要响应性,不需要使用 ref()
const links = [
{
name: 'about',
href: '/about'
},
{
name: 'terms of service',
href: '/tos'
},
{
name: 'contact us',
href: '/contact'
}
]
// 需要响应性,使用 ref()
const tabs = ref([
{
name: 'Privacy',
url: '/privacy',
isActive: true
},
{
name: 'Permissions',
url: '/permissions',
isActive: false
}
])
</script>
使用 v-bind 同名简写
Vue 3.4 引入了 v-bind 同名简写,进一步简化了代码。
<template>
<!-- 之前 -->
<img :id="id" :src="src" :alt="alt">
<!-- 现在 -->
<img :id :src :alt>
</template>
使用 shallowRef 优化性能
对于不需要深度响应性的大型数据结构,可以使用 shallowRef 来优化性能。
const state = shallowRef({ count: 1 })
// 不会触发更新
state.value.count = 2
// 会触发更新
state.value = { count: 2 }
类型化组件 emits
通过类型化 emits,可以获得更好的错误处理和编辑器支持。
const emit = defineEmits<{
change: [id: number]
update: [value: string]
}>()
在 <style> 中使用 v-bind
Vue 允许在 <style> 中使用 v-bind 来绑定动态值,并且它是完全响应式的。
<style scoped>
button {
background-color: v-bind(backgroundColor);
}
</style>
使用 Tanstack Query 简化数据获取
Tanstack Query(Vue Query)可以大大减少数据获取的样板代码,并提供自动缓存、自动重新获取等强大功能。
// 之前的数据获取模式
const posts = ref([]);
const isLoading = ref(false);
const isError = ref(false);
async function fetchPosts() {
isLoading.value = true;
isError.value = false;
try {
const response = await fetch('someurl');
posts.value = await response.json();
} catch(error) {
isError.value = true;
} finally {
isLoading.value = false;
}
}
onMounted(() => {
fetchPosts();
})
// 使用 Tanstack Query 简化
const {data: posts, isLoading, isError} = useQuery({
queryKey: ['posts'],
queryFn: fetchPosts
})
async function fetchPosts() {
const response = await fetch('someurl');
const data = await response.json();
return data;
}
使用 :global 伪类应用全局样式
在 Vue 中,使用 :global 伪类可以在局部样式中应用全局样式。
<style scoped>
:global(.red) {
color: red;
}
</style>
使用 withDefaults 设置默认值
即使在使用类型声明的 defineProps 时,也可以使用 withDefaults 宏来设置默认值。
<script setup lang="ts">
export interface Props {
variant?: 'primary' | 'secondary'
disabled?: boolean
}
const props = withDefaults(defineProps<Props>(), {
variant: 'primary',
disabled: false
})
</script>
自定义指令
在 Vue 中,可以通过创建一个包含生命周期钩子的对象来注册自定义指令。
<script setup>
// 在模板中启用 v-focus
const vFocus = {
mounted: (el) => el.focus()
}
</script>
<template>
<input v-focus />
</template>
使用 :deep() 伪类影响子组件样式
在局部样式中,使用 :deep() 伪类可以影响子组件的样式。
<style scoped>
.a :deep(.b) {
/* ... */
}
</style>
使用 :slotted 伪类针对插槽内容
默认情况下,局部样式不会影响通过 <slot/> 渲染的内容。使用 :slotted 伪类可以显式地针对插槽内容。
<style scoped>
:slotted(div) {
color: red;
}
</style>
使用 <KeepAlive> 缓存组件状态
在 Vue.js 中,默认情况下,切换组件时会卸载当前组件。使用 <KeepAlive> 可以缓存组件状态。
<template>
<KeepAlive>
<component :is="activeComponent" />
</KeepAlive>
</template>
传递多个具名插槽
在 Vue.js 中,可以向子组件传递多个具名插槽。
<!-- 子组件 / Input.vue -->
<template>
<div class="input-wrapper">
<label>
<slot name="label" />
</label>
<input />
<div class="input-icon">
<slot name="icon" />
</div>
</div>
</template>
<!-- 父组件 -->
<template>
<Input>
<template #label>
Email
</template>
<template #icon>
<EmailIcon />
</template>
</Input>
</template>
使用 Suspense 处理异步依赖
通过实验性的 Suspense 组件,可以在组件树中协调异步依赖,并在等待多个嵌套异步依赖解析时渲染加载状态。
<template>
<Suspense>
<!-- 包含嵌套异步依赖的组件 -->
<Dashboard />
<!-- 通过 #fallback 插槽显示加载状态 -->
<template #fallback>
Loading...
</template>
</Suspense>
</template>
使用 Teleport 传送模板部分
在 Vue 中,可以使用内置的 Teleport 组件将模板的一部分传送到组件 DOM 层次结构之外的 DOM 节点。
<template>
<Teleport to="body">
<div v-if="open" class="modal">
<p>Hello from the modal!</p>
<button @click="open = false">Close</button>
</div>
</Teleport>
</template>
启用性能追踪
在 Vue 中,可以在浏览器开发者工具的性能/时间线面板中启用性能追踪。这仅在开发模式下有效。
const app = createApp(App);
app.config.performance = true;
app.mount('#app');
动态渲染组件
在 Vue 中,可以使用内置的 <Component> 组件动态渲染组件。
<script setup>
import UserSettings from './Foo.vue'
import UserNotifications from './Bar.vue'
const activeComponent = ref(UserSettings);
</script>
<template>
<component :is="activeComponent" />
</template>
布尔类型 prop 的简写
在 Vue 中,当传递布尔类型的 prop 且值为 true 时,可以使用简写形式。
<template>
<!-- 可以使用这种形式 -->
<BlogPost is-published />
<!-- 而不是这种形式 -->
<BlogPost :is-published="true" />
</template>
使用 v-model 修饰符
默认情况下,v-model 在每次 input 事件后同步数据。可以使用 lazy 修饰符改为在 change 事件后同步。
<!-- 在 "change" 事件后同步 -->
<input v-model.lazy="msg" />
自动类型转换
如果希望用户输入自动转换为数字,可以在 v-model 上添加 number 修饰符。
<input v-model.number="age" />
自动修剪空格
如果希望自动修剪用户输入的空格,可以在 v-model 上添加 trim 修饰符。
<input v-model.trim="msg" />
使用 defineExpose 暴露属性
在 <script setup> 组件中,默认是关闭的。使用 defineExpose 编译器宏可以显式暴露属性。
<script setup>
import { ref } from 'vue'
const a = 1
const b = ref(2)
defineExpose({
a,
b
})
</script>
合并类和样式
在 Vue 中,当组件模板中有一些类,并且在父组件中也添加了一些类时,这些类会自动合并。
<!-- 父组件 -->
<template>
<Table class="py-2"></Table>
</template>
<!-- 子组件 Table.vue -->
<template>
<table class="border-solid border-2 border-sky-500">
<!-- ... -->
</table>
</template>
<!-- 合并后的类 -->
<template>
<table class="border-solid border-2 border-sky-500 py-2">
<!-- ... -->
</table>
</template>
启用自定义格式化器
在 Vue 中,启用自定义格式化器可以在控制台中更好地查看响应式数据。可以在 Chrome 浏览器的开发者工具中启用自定义格式化器,选择 Console -> custom formatters。
参考:https://vuejstips.com/