2025年 Vue 開發(fā)必備的25個超實用技巧!
本文來分享 25 個 Vue 開發(fā)必備的實用技巧!
使用 defineModel() 實現(xiàn)雙向數(shù)據(jù)綁定
在 Vue 3.4 中,推薦使用 defineModel() 宏來實現(xiàn)雙向數(shù)據(jù)綁定,這大大簡化了代碼。
<!-- 使用 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(),只有在需要響應(yīng)性時才使用。
<script setup>
// 不需要響應(yīng)性,不需要使用 ref()
const links = [
{
name: 'about',
href: '/about'
},
{
name: 'terms of service',
href: '/tos'
},
{
name: 'contact us',
href: '/contact'
}
]
// 需要響應(yīng)性,使用 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">
<!-- 現(xiàn)在 -->
<img :id :src :alt>
</template>
使用 shallowRef 優(yōu)化性能
對于不需要深度響應(yīng)性的大型數(shù)據(jù)結(jié)構(gòu),可以使用 shallowRef 來優(yōu)化性能。
const state = shallowRef({ count: 1 })
// 不會觸發(fā)更新
state.value.count = 2
// 會觸發(fā)更新
state.value = { count: 2 }
類型化組件 emits
通過類型化 emits,可以獲得更好的錯誤處理和編輯器支持。
const emit = defineEmits<{
change: [id: number]
update: [value: string]
}>()
在 <style> 中使用 v-bind
Vue 允許在 <style> 中使用 v-bind 來綁定動態(tài)值,并且它是完全響應(yīng)式的。
<style scoped>
button {
background-color: v-bind(backgroundColor);
}
</style>
使用 Tanstack Query 簡化數(shù)據(jù)獲取
Tanstack Query(Vue Query)可以大大減少數(shù)據(jù)獲取的樣板代碼,并提供自動緩存、自動重新獲取等強大功能。
// 之前的數(shù)據(jù)獲取模式
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 偽類應(yīng)用全局樣式
在 Vue 中,使用 :global 偽類可以在局部樣式中應(yīng)用全局樣式。
<style scoped>
:global(.red) {
color: red;
}
</style>
使用 withDefaults 設(shè)置默認值
即使在使用類型聲明的 defineProps 時,也可以使用 withDefaults 宏來設(shè)置默認值。
<script setup lang="ts">
export interface Props {
variant?: 'primary' | 'secondary'
disabled?: boolean
}
const props = withDefaults(defineProps<Props>(), {
variant: 'primary',
disabled: false
})
</script>
自定義指令
在 Vue 中,可以通過創(chuàng)建一個包含生命周期鉤子的對象來注冊自定義指令。
<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 偽類針對插槽內(nèi)容
默認情況下,局部樣式不會影響通過 <slot/> 渲染的內(nèi)容。使用 :slotted 偽類可以顯式地針對插槽內(nèi)容。
<style scoped>
:slotted(div) {
color: red;
}
</style>
使用 <KeepAlive> 緩存組件狀態(tài)
在 Vue.js 中,默認情況下,切換組件時會卸載當前組件。使用 <KeepAlive> 可以緩存組件狀態(tài)。
<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 組件,可以在組件樹中協(xié)調(diào)異步依賴,并在等待多個嵌套異步依賴解析時渲染加載狀態(tài)。
<template>
<Suspense>
<!-- 包含嵌套異步依賴的組件 -->
<Dashboard />
<!-- 通過 #fallback 插槽顯示加載狀態(tài) -->
<template #fallback>
Loading...
</template>
</Suspense>
</template>
使用 Teleport 傳送模板部分
在 Vue 中,可以使用內(nèi)置的 Teleport 組件將模板的一部分傳送到組件 DOM 層次結(jié)構(gòu)之外的 DOM 節(jié)點。
<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 中,可以在瀏覽器開發(fā)者工具的性能/時間線面板中啟用性能追蹤。這僅在開發(fā)模式下有效。
const app = createApp(App);
app.config.performance = true;
app.mount('#app');
動態(tài)渲染組件
在 Vue 中,可以使用內(nèi)置的 <Component> 組件動態(tài)渲染組件。
<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 事件后同步數(shù)據(jù)。可以使用 lazy 修飾符改為在 change 事件后同步。
<!-- 在 "change" 事件后同步 -->
<input v-model.lazy="msg" />
自動類型轉(zhuǎn)換
如果希望用戶輸入自動轉(zhuǎn)換為數(shù)字,可以在 v-model 上添加 number 修飾符。
<input v-model.number="age" />
自動修剪空格
如果希望自動修剪用戶輸入的空格,可以在 v-model 上添加 trim 修飾符。
<input v-model.trim="msg" />
使用 defineExpose 暴露屬性
在 <script setup> 組件中,默認是關(guān)閉的。使用 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 中,啟用自定義格式化器可以在控制臺中更好地查看響應(yīng)式數(shù)據(jù)??梢栽?Chrome 瀏覽器的開發(fā)者工具中啟用自定義格式化器,選擇 Console -> custom formatters。
參考:https://vuejstips.com/