Vue3 常用功能学习笔记

738 阅读2分钟

Vue3在实际项目开发中,高频使用到的相关的内容。

一、Composition API(核心范式)

替代 Options API 的逻辑组织方式,更适合复杂组件和逻辑复用。

<script setup>
import { ref, computed, onMounted } from 'vue'

// 1. 响应式数据
const count = ref(0) // 基本类型
const user = ref({ name: 'Alice', age: 30 }) // 对象类型

// 2. 计算属性
const doubledCount = computed(() => count.value * 2)

// 3. 方法
const increment = () => {
  count.value++
  user.value.age++ // 自动触发更新
}

// 4. 生命周期
onMounted(() => {
  console.log('组件挂载完成,初始计数:', count.value)
})

// 5. 暴露给模板
defineExpose({ increment }) // 父组件可通过ref调用
</script>

<template>
  <button @click="increment">
    {{ count }} - 双倍: {{ doubledCount }}
  </button>
  <p>{{ user.name }} 年龄: {{ user.age }}</p>
</template>

二、响应式进阶

1. ref vs reactive

// ref:通用类型,通过.value访问
const num = ref(42)

// reactive:仅对象类型(无.value)
const state = reactive({
  items: [],
  loading: false
})

// 解构响应式对象(保持响应性)
import { toRefs } from 'vue'
const { items, loading } = toRefs(state)

2. 深度监听(watchEffect 和 watch)

// 自动依赖跟踪
watchEffect(() => {
  console.log('计数变化:', count.value)
})

// 精确监听
watch(
  () => user.value.age,
  (newAge, oldAge) => {
    alert(`年龄从 ${oldAge} 变为 ${newAge}`)
  },
  { deep: true } // 深度监听对象内部变化
)

三、组件通信

1. Props + Emits

<!-- Parent.vue -->
<Child :title="pageTitle" @update-title="handleUpdate" />

<!-- Child.vue -->
<script setup>
defineProps(['title'])
const emit = defineEmits(['update-title'])

const changeTitle = () => {
  emit('update-title', '新标题-' + Date.now())
}
</script>

2. 依赖注入(Provide/Inject)

// 祖先组件
import { provide, ref } from 'vue'
const globalConfig = ref({ theme: 'dark' })
provide('appConfig', globalConfig)

// 后代组件
import { inject } from 'vue'
const config = inject('appConfig')
console.log(config.value.theme) // 'dark'

四、状态管理(Pinia 示例)

// stores/counter.js
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  actions: {
    increment() {
      this.count++
    }
  },
  getters: {
    doubleCount: (state) => state.count * 2
  }
})

// 组件中使用
import { useCounterStore } from '@/stores/counter'
const store = useCounterStore()

// 读取状态
console.log(store.doubleCount)

// 修改状态
store.increment()

// 订阅变化
store.$subscribe((mutation) => {
  console.log('状态变化:', mutation)
})

五、路由管理(Vue Router 4)

// router.js
import { createRouter, createWebHistory } from 'vue-router'

const routes = [
  {
    path: '/user/:id',
    component: () => import('./views/User.vue'),
    props: true // 自动将路由参数转为props
  }
]

const router = createRouter({
  history: createWebHistory(),
  routes
})

// 组件内获取路由信息
import { useRoute, useRouter } from 'vue-router'

const route = useRoute()
console.log('用户ID:', route.params.id)

const router = useRouter()
router.push({ name: 'home' })

六、异步处理最佳实践

<script setup>
import { ref } from 'vue'

const data = ref(null)
const error = ref(null)
const loading = ref(false)

const fetchData = async () => {
  try {
    loading.value = true
    const res = await fetch('https://api.example.com/data')
    data.value = await res.json()
  } catch (err) {
    error.value = err.message
  } finally {
    loading.value = false
  }
}
</script>

<template>
  <div v-if="loading">加载中...</div>
  <div v-else-if="error">错误: {{ error }}</div>
  <div v-else>{{ data }}</div>
</template>

七、组件复用(Composables)

// composables/useMouse.js
import { onMounted, onUnmounted, ref } from 'vue'

export function useMouse() {
  const x = ref(0)
  const y = ref(0)

  const update = e => {
    x.value = e.pageX
    y.value = e.pageY
  }

  onMounted(() => window.addEventListener('mousemove', update))
  onUnmounted(() => window.removeEventListener('mousemove', update))

  return { x, y }
}

// 组件中使用
import { useMouse } from './useMouse'
const { x, y } = useMouse()

八、性能优化技巧

<template>
  <!-- 1. v-once 静态内容优化 -->
  <div v-once>{{ staticText }}</div>
  
  <!-- 2. 虚拟滚动长列表 -->
  <RecycleScroller
    v-slot="{ item }"
    :items="bigList"
    item-size="50"
    class="scroller"
  >
    {{ item.name }}
  </RecycleScroller>
  
  <!-- 3. KeepAlive 缓存组件 -->
  <KeepAlive include="TabComponent">
    <component :is="currentComponent" />
  </KeepAlive>
</template>

<script>
// 4. 组件懒加载
import { defineAsyncComponent } from 'vue'
const HeavyComponent = defineAsyncComponent(() => 
  import('./HeavyComponent.vue')
)
</script>

九、TypeScript 集成

<script setup lang="ts">
interface User {
  id: number
  name: string
  email?: string
}

// 类型化props
const props = defineProps<{
  title: string
  user: User
}>()

// 类型化emits
const emit = defineEmits<{
  (e: 'update', payload: User): void
}>()
</script>

十、调试技巧

// 1. 自定义 Ref 调试器
import { ref } from 'vue'

const debugRef = (target, label = 'Debug Ref') => {
  return ref({
    get value() {
      console.log(`${label} Get:`, target.value)
      return target.value
    },
    set value(newVal) {
      console.log(`${label} Set:`, newVal)
      target.value = newVal
    }
  })
}

// 2. Vue Devtools 时间线记录
import { nextTick } from 'vue'
nextTick(() => {
  performance.mark('custom-event-end')
})

这些功能涵盖了 Vue3 开发的 90% 日常使用场景。最佳实践建议:

  1. 中小项目优先使用 Composition API + Provide/Inject
  2. 复杂状态使用 Pinia 替代 Vuex
  3. 逻辑复用使用 Composables
  4. 性能敏感场景使用 <script setup> 语法
  5. 类型安全优先使用 TypeScript

新项目推荐技术栈:

  • 构建工具:Vite
  • 状态管理:Pinia
  • 路由:Vue Router 4
  • UI 库:Element Plus / Naive UI
  • 代码规范:ESLint + Prettier