2025年 Vue 开发必备的25个超实用技巧!

作者: jie 分类: Vue 发布时间: 2025-02-18 14:02

本文来分享 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。

发表回复