Vue 3 的 18 个实用技巧
让你从 Vue 新手秒变老司机的实用秘籍!
1. Composition API 优雅组织代码
Before(选项式API - 代码分散):
exportdefault {
data() {
return { count: 0, name: '' }
},
methods: {
increment() { this.count++ }
},
computed: {
doubleCount() { returnthis.count * 2 }
},
mounted() { console.log('组件挂载') }
}
After(组合式API - 逻辑集中):
import { ref, computed, onMounted } from'vue'exportdefault {
setup() {
const count = ref(0)
const name = ref('')
const doubleCount = computed(() => count.value * 2)
const increment = () => { count.value++ }
onMounted(() => { console.log('组件挂载') })
return { count, name, doubleCount, increment }
}
}
2. <script setup> 语法糖 - 真香!
<script setup>
import { ref, computed } from 'vue'// 变量自动暴露给模板
const count = ref(0)
const name = ref('Vue3')
// 函数自动暴露
const increment = () => { count.value++ }
// 计算属性自动暴露
const greeting = computed(() => `Hello, ${name.value}!`)
// 组件自动注册(无需components选项)
import MyComponent from './MyComponent.vue'
</script>
<template>
<div>
<MyComponent />
<button @click="increment">{{ count }}</button>
<p>{{ greeting }}</p>
</div>
</template>
3. reactive 和 ref 的正确选择
import { ref, reactive } from'vue'// ✅ ref 用于基本类型
const count = ref(0)
const name = ref('')
// ✅ reactive 用于对象
const user = reactive({
name: '张三',
age: 25,
address: {
city: '北京'
}
})
// ❌ 不要这样用 reactive
const count = reactive({ value: 0 }) // 太啰嗦!
// ✅ 正确:解构 reactive 保持响应性
import { toRefs } from'vue'
const { name, age } = toRefs(user)
4. 计算属性的高级用法
<script setup>
import { ref, computed } from 'vue'const price = ref(100)
const quantity = ref(2)
const discount = ref(0.1)
// 可写的计算属性
const total = computed({
get: () => price.value * quantity.value * (1 - discount.value),
set: (value) => {
price.value = value / quantity.value / (1 - discount.value)
}
})
// 修改 total 会自动更新 price
const updatePrice = () => {
total.value = 500 // 自动重新计算 price
}
</script>
5. Watch 的精准监听
<script setup>
import { ref, watch, watchEffect } from 'vue'const count = ref(0)
const user = reactive({ name: '张三', age: 25 })
// 1. 监听单个 ref
watch(count, (newVal, oldVal) => {
console.log(`count从${oldVal}变为${newVal}`)
})
// 2. 监听多个值
watch([count, () => user.name], ([newCount, newName], [oldCount, oldName]) => {
console.log('count或name变化了')
})
// 3. 深度监听对象
watch(user, (newUser) => {
console.log('user对象变化了', newUser)
}, { deep: true })
// 4. watchEffect - 自动追踪依赖
watchEffect(() => {
console.log(`count是${count.value}, name是${user.name}`)
// 自动追踪 count 和 user.name 的变化
})
</script>
6. 组件通信的多种方式
Props + Emits(父子通信)
<!-- 子组件 -->
<script setup>
defineProps(['title', 'count'])
defineEmits(['update:title', 'count-change'])const updateTitle = () => {
// 触发事件更新父组件
emit('update:title', '新标题')
}
</script>
<!-- 父组件 -->
<template>
<ChildComponent
:title="pageTitle"
:count="pageCount"
@update:title="pageTitle = $event"
@count-change="handleCountChange"
/>
</template>
provide/inject(跨级通信)
<!-- 祖先组件 -->
<script setup>
import { provide, ref } from 'vue'const theme = ref('dark')
const user = ref({ name: '张三' })
// 提供数据给所有后代组件
provide('theme', theme)
provide('user', user)
provide('updateTheme', (newTheme) => {
theme.value = newTheme
})
</script>
<!-- 后代组件 -->
<script setup>
import { inject } from 'vue'
const theme = inject('theme')
const user = inject('user')
const updateTheme = inject('updateTheme')
// 修改主题
const toggleTheme = () => {
updateTheme(theme.value === 'dark' ? 'light' : 'dark')
}
</script>
7. 自定义 Hooks - 逻辑复用神器
// hooks/useCounter.js
import { ref, computed } from'vue'exportfunctionuseCounter(initialValue = 0) {
const count = ref(initialValue)
const increment = () => count.value++
const decrement = () => count.value--
const reset = () => count.value = initialValue
const double = computed(() => count.value * 2)
return { count, increment, decrement, reset, double }
}
// 在组件中使用
<script setup>
import { useCounter } from'@/hooks/useCounter'
const { count, increment, double } = useCounter(10)
</script>
8. 模板引用(Template Refs)技巧
<template>
<input ref="inputRef" type="text">
<div ref="divRef">内容</div>
<ChildComponent ref="childRef" /> <!-- 动态 ref -->
<div v-for="item in list" :ref="setItemRef">
{{ item }}
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
// 1. 静态 ref
const inputRef = ref(null)
const divRef = ref(null)
const childRef = ref(null)
// 2. 动态 ref 数组
const itemRefs = ref([])
const setItemRef = el => {
if (el) itemRefs.value.push(el)
}
onMounted(() => {
// 组件挂载后可以访问 DOM 元素
inputRef.value.focus()
console.log(childRef.value) // 子组件实例
})
</script>
9. 条件渲染的性能优化
<template>
<!-- ✅ 使用 v-show 频繁切换 -->
<div v-show="isVisible">频繁显示隐藏的内容</div> <!-- ✅ 使用 v-if 初始条件 -->
<div v-if="hasData">一次性判断的内容</div>
<!-- ✅ 使用 Teleport 传送门 -->
<Teleport to="body">
<Modal v-if="showModal" />
</Teleport>
<!-- ✅ 使用 Suspense 异步组件 -->
<Suspense>
<template #default>
<AsyncComponent />
</template>
<template #fallback>
<div>加载中...</div>
</template>
</Suspense>
</template>
10. 样式和作用域技巧
<template>
<div class="container" :class="{ active: isActive, 'text-error': hasError }">
<p :style="{ color: textColor, fontSize: fontSize + 'px' }">动态样式</p>
</div>
</template><style scoped>
/* 作用域样式 */
.container {
padding: 20px;
}
/* 深度选择器 */
.container :deep(.child-element) {
color: red;
}
/* 全局样式 */
.container :global(.global-class) {
margin: 10px;
}
/* CSS 变量 */
.container {
--primary-color: #42b983;
color: var(--primary-color);
}
</style>
11. 事件处理的高级技巧
<template>
<!-- 事件修饰符 -->
<button @click.stop="handleClick">阻止冒泡</button>
<form @submit.prevent="handleSubmit">阻止默认</form>
<input @keyup.enter="submit" @keyup.esc="cancel"> <!-- 多个事件 -->
<div @click="handleClick" @mouseenter="handleMouseEnter"></div>
<!-- 自定义事件 -->
<MyComponent @custom-event="handleCustom" />
</template>
<script setup>
// 事件处理函数
const handleClick = (event) => {
console.log('点击事件', event.target)
}
// 带参数的事件
const handleItemClick = (item, index, event) => {
console.log('点击项目:', item, index)
}
</script>
12. 生命周期的最佳实践
<script setup>
import { onMounted, onUnmounted, onUpdated } from 'vue'// 组件挂载
onMounted(() => {
console.log('组件挂载完成')
// 初始化操作、监听事件、获取数据
window.addEventListener('resize', handleResize)
})
// 组件更新
onUpdated(() => {
console.log('组件更新了')
// DOM 更新后的操作
})
// 组件卸载
onUnmounted(() => {
console.log('组件卸载')
// 清理操作:移除事件监听、清除定时器
window.removeEventListener('resize', handleResize)
})
// 错误处理
onErrorCaptured((error) => {
console.error('捕获到错误:', error)
return false // 阻止错误继续向上传播
})
</script>
13. 路由和状态管理技巧
<script setup>
import { useRoute, useRouter } from 'vue-router'
import { useStore } from 'vuex'const route = useRoute()
const router = useRouter()
const store = useStore()
// 路由操作
const goToUser = (userId) => {
router.push(`/user/${userId}`)
}
// 状态管理
const user = computed(() => store.state.user)
const updateUser = () => {
store.dispatch('user/updateUser', { name: '新名字' })
}
// 监听路由变化
watch(() => route.params.id, (newId) => {
if (newId) {
loadUserData(newId)
}
})
</script>
14. TypeScript 支持
<script setup lang="ts">
import { ref, computed } from 'vue'// 类型定义
interface User {
id: number
name: string
email: string
}
// 带类型的 ref
const user = ref<User>({
id: 1,
name: '张三',
email: '[email protected]'
})
// 带类型的 props
interface Props {
title: string
count?: number
items: User[]
}
const props = withDefaults(defineProps<Props>(), {
count: 0
})
// 带类型的 emits
const emit = defineEmits<{
(e: 'update:title', value: string): void
(e: 'submit', data: User): void
}>()
// 带类型的计算属性
const userName = computed<string>(() => user.value.name.toUpperCase())
</script>
15. 性能优化技巧
<script setup>
import { shallowRef, markRaw } from 'vue'// 1. 浅层响应式(不深度监听)
const largeObject = shallowRef({ /* 大数据对象 */ })
// 2. 标记非响应式对象
const heavyInstance = markRaw(new HeavyClass())
// 3. 懒加载组件
const HeavyComponent = defineAsyncComponent(() =>
import('./HeavyComponent.vue')
)
// 4. 计算属性缓存
const expensiveValue = computed(() => {
return heavyCalculation(props.data)
})
// 5. 防抖操作
import { debounce } from 'lodash-es'
const search = debounce((query) => {
// 搜索逻辑
}, 300)
</script>
16. 错误边界和调试
<template>
<ErrorBoundary>
<Suspense>
<ComponentThatMightError />
</Suspense>
</ErrorBoundary>
</template><script setup>
// 错误处理
const handleError = (error) => {
console.error('组件错误:', error)
// 上报错误到监控系统
}
// 开发环境调试
const debug = (message, ...args) => {
if (import.meta.env.DEV) {
console.log(`[DEBUG] ${message}`, ...args)
}
}
// 使用调试函数
debug('组件状态:', { count, user })
</script>
17. 第三方库集成
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'// 图表库集成
const chartRef = ref(null)
let chartInstance = null
onMounted(() => {
chartInstance = echarts.init(chartRef.value)
chartInstance.setOption({
// 图表配置
})
})
onUnmounted(() => {
chartInstance?.dispose()
})
// UI 库集成
import { ElMessage } from 'element-plus'
const showMessage = () => {
ElMessage.success('操作成功!')
}
// 工具库集成
import { cloneDeep, throttle } from 'lodash-es'
const throttledSearch = throttle((query) => {
// 搜索逻辑
}, 300)
</script>
18. 项目结构和最佳实践
src/
├── components/ # 公共组件
│ ├── base/ # 基础组件
│ └── business/ # 业务组件
├── views/ # 页面组件
├── composables/ # 组合式函数
├── stores/ # 状态管理
├── utils/ # 工具函数
├── types/ # 类型定义
└── assets/ # 静态资源
最佳实践总结:
使用 <script setup>语法合理选择 ref和reactive逻辑复用使用自定义 Hooks 类型安全使用 TypeScript 性能优化使用懒加载和浅层响应 错误处理使用错误边界 保持组件单一职责
掌握这 18 个技巧,你的 Vue 3 开发水平将大幅提升!🎯