前端-Vue基础知识

6 阅读3分钟

Vue 基础知识(Vue 2 & Vue 3)


一、Vue 概述

1.1 什么是 Vue

Vue 是一套用于构建用户界面的渐进式 JavaScript 框架。

核心特点:

  • 响应式数据绑定
  • 组件化开发
  • 虚拟 DOM
  • 指令系统
  • 单文件组件(SFC)

1.2 Vue 版本对比

特性Vue 2Vue 3
发布时间2016 年2020 年
性能较慢更快(约 2 倍)
包大小较大更小(Tree-shaking)
Composition API
TypeScript支持有限原生支持
响应式系统Object.definePropertyProxy
生命周期Options APIOptions API + Composition API

二、快速开始

2.1 Vue 2 安装

<!-- CDN 引入 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>

<!-- 或使用 npm -->
npm install vue@2
// Vue 2 使用
new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue 2'
  }
})

2.2 Vue 3 安装

<!-- CDN 引入 -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>

<!-- 或使用 npm -->
npm install vue@3
// Vue 3 使用
import { createApp } from 'vue'

createApp({
  data() {
    return {
      message: 'Hello Vue 3'
    }
  }
}).mount('#app')

2.3 单文件组件(SFC)

<template>
  <div class="hello">
    <h1>{{ message }}</h1>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data() {
    return {
      message: 'Hello Vue'
    }
  }
}
</script>

<style scoped>
.hello {
  color: #42b983;
}
</style>

三、模板语法

3.1 插值

Vue 2 & Vue 3(相同):

<template>
  <!-- 文本插值 -->
  <p>{{ message }}</p>
  
  <!-- 原始 HTML -->
  <div v-html="rawHtml"></div>
  
  <!-- 属性绑定 -->
  <div :id="dynamicId"></div>
  <img :src="imageUrl" />
  
  <!-- 布尔属性 -->
  <button :disabled="isDisabled">按钮</button>
</template>

3.2 指令

v-if / v-show:

<template>
  <!-- v-if:条件渲染 -->
  <div v-if="type === 'A'">A</div>
  <div v-else-if="type === 'B'">B</div>
  <div v-else>C</div>
  
  <!-- v-show:切换 display -->
  <div v-show="isVisible">可见</div>
</template>

v-for:

<template>
  <!-- 遍历数组 -->
  <li v-for="(item, index) in items" :key="item.id">
    {{ index }}: {{ item.name }}
  </li>
  
  <!-- 遍历对象 -->
  <div v-for="(value, key) in object" :key="key">
    {{ key }}: {{ value }}
  </div>
</template>

v-on(事件):

<template>
  <!-- 方法处理 -->
  <button @click="handleClick">点击</button>
  
  <!-- 内联处理 -->
  <button @click="count++">+1</button>
  
  <!-- 传参 -->
  <button @click="handleClick(item, $event)">点击</button>
  
  <!-- 事件修饰符 -->
  <form @submit.prevent="onSubmit"></form>
  <div @click.stop="onClick"></div>
  <button @click.once="doOnce"></button>
</template>

v-model(双向绑定):

<template>
  <!-- 文本 -->
  <input v-model="message" />
  
  <!-- 多行文本 -->
  <textarea v-model="content"></textarea>
  
  <!-- 复选框 -->
  <input type="checkbox" v-model="checked" />
  
  <!-- 单选 -->
  <input type="radio" value="one" v-model="picked" />
  
  <!-- 下拉 -->
  <select v-model="selected">
    <option value="a">A</option>
    <option value="b">B</option>
  </select>
  
  <!-- 修饰符 -->
  <input v-model.lazy="msg" />
  <input v-model.number="age" />
  <input v-model.trim="name" />
</template>

四、响应式数据

4.1 Vue 2(Options API)

export default {
  data() {
    return {
      message: 'Hello',
      count: 0,
      user: {
        name: 'zhangsan',
        age: 25
      },
      items: [1, 2, 3]
    }
  },
  
  computed: {
    // 计算属性
    doubleCount() {
      return this.count * 2
    }
  },
  
  watch: {
    // 侦听器
    count(newVal, oldVal) {
      console.log(`count 从 ${oldVal} 变为 ${newVal}`)
    }
  },
  
  methods: {
    increment() {
      this.count++
    }
  }
}

4.2 Vue 3(Composition API)

import { ref, reactive, computed, watch } from 'vue'

export default {
  setup() {
    // ref:基本类型
    const count = ref(0)
    const message = ref('Hello')
    
    // reactive:对象
    const user = reactive({
      name: 'zhangsan',
      age: 25
    })
    
    // 计算属性
    const doubleCount = computed(() => count.value * 2)
    
    // 侦听器
    watch(count, (newVal, oldVal) => {
      console.log(`count 从 ${oldVal} 变为 ${newVal}`)
    })
    
    // 方法
    const increment = () => {
      count.value++
    }
    
    return {
      count,
      message,
      user,
      doubleCount,
      increment
    }
  }
}

4.3 Vue 3(<script setup> 语法糖)

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

// ref
const count = ref(0)
const message = ref('Hello')

// reactive
const user = reactive({
  name: 'zhangsan',
  age: 25
})

// computed
const doubleCount = computed(() => count.value * 2)

// watch
watch(count, (newVal, oldVal) => {
  console.log(`count 从 ${oldVal} 变为 ${newVal}`)
})

// methods
const increment = () => {
  count.value++
}
</script>

4.4 ref vs reactive

特性refreactive
适用类型基本类型 + 对象仅对象/数组
访问方式.value直接访问
重新赋值✅ 可以❌ 会丢失响应性
解构保持响应性需要 toRefs
// ref 示例
const count = ref(0)
count.value++ // 正确

// reactive 示例
const state = reactive({ count: 0 })
state.count++ // 正确

// 解构 reactive
const { count } = toRefs(state)
count.value++ // 正确

五、计算属性和侦听器

5.1 计算属性(Computed)

Vue 2:

export default {
  data() {
    return {
      firstName: '张',
      lastName: '三'
    }
  },
  computed: {
    fullName() {
      return this.firstName + this.lastName
    },
    // 可写计算属性
    fullNameRW: {
      get() {
        return this.firstName + this.lastName
      },
      set(value) {
        const names = value.split(' ')
        this.firstName = names[0]
        this.lastName = names[1]
      }
    }
  }
}

Vue 3:

import { ref, computed } from 'vue'

const firstName = ref('张')
const lastName = ref('三')

// 只读
const fullName = computed(() => firstName.value + lastName.value)

// 可写
const fullNameRW = computed({
  get: () => firstName.value + lastName.value,
  set: (val) => {
    const names = val.split(' ')
    firstName.value = names[0]
    lastName.value = names[1]
  }
})

5.2 侦听器(Watch)

Vue 2:

export default {
  data() {
    return {
      count: 0,
      user: { name: 'zhangsan', age: 25 }
    }
  },
  watch: {
    // 基础用法
    count(newVal, oldVal) {
      console.log(`${oldVal} -> ${newVal}`)
    },
    // 深度监听
    user: {
      handler(newVal, oldVal) {
        console.log('user changed')
      },
      deep: true,
      immediate: true
    },
    // 监听对象属性
    'user.name'(newVal) {
      console.log('name changed:', newVal)
    }
  }
}

Vue 3:

import { ref, watch, watchEffect } from 'vue'

const count = ref(0)
const user = ref({ name: 'zhangsan', age: 25 })

// 基础用法
watch(count, (newVal, oldVal) => {
  console.log(`${oldVal} -> ${newVal}`)
})

// 配置选项
watch(count, callback, {
  immediate: true,
  deep: true,
  flush: 'post'
})

// 监听多个
watch([count, user], ([newCount, newUser], [oldCount, oldUser]) => {
  console.log('changed')
})

// watchEffect:自动追踪依赖
watchEffect(() => {
  console.log('count:', count.value)
})

六、生命周期

6.1 Vue 2 生命周期

export default {
  beforeCreate() {
    // 实例初始化之前
  },
  created() {
    // 实例创建完成,数据已初始化
  },
  beforeMount() {
    // 挂载之前
  },
  mounted() {
    // 挂载完成,可访问 DOM
  },
  beforeUpdate() {
    // 数据更新,DOM 更新前
  },
  updated() {
    // DOM 更新后
  },
  beforeDestroy() {
    // 销毁前(Vue 3 改为 beforeUnmount)
  },
  destroyed() {
    // 销毁后(Vue 3 改为 unmounted)
  }
}

6.2 Vue 3 生命周期

Options API(与 Vue 2 类似):

export default {
  beforeCreate() { },
  created() { },
  beforeMount() { },
  mounted() { },
  beforeUpdate() { },
  updated() { },
  beforeUnmount() { },  // Vue 2 是 beforeDestroy
  unmounted() { }        // Vue 2 是 destroyed
}

Composition API:

import {
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted
} from 'vue'

export default {
  setup() {
    onBeforeMount(() => {
      console.log('挂载前')
    })
    
    onMounted(() => {
      console.log('已挂载')
    })
    
    onBeforeUpdate(() => {
      console.log('更新前')
    })
    
    onUpdated(() => {
      console.log('已更新')
    })
    
    onBeforeUnmount(() => {
      console.log('卸载前')
    })
    
    onUnmounted(() => {
      console.log('已卸载')
    })
  }
}

生命周期对比:

Vue 2Vue 3 (Options)Vue 3 (Composition)
beforeCreatebeforeCreatesetup()
createdcreatedsetup()
beforeMountbeforeMountonBeforeMount
mountedmountedonMounted
beforeUpdatebeforeUpdateonBeforeUpdate
updatedupdatedonUpdated
beforeDestroybeforeUnmountonBeforeUnmount
destroyedunmountedonUnmounted

七、组件

7.1 组件注册

Vue 2:

// 全局注册
Vue.component('MyComponent', {
  // 选项
})

// 局部注册
export default {
  components: {
    MyComponent
  }
}

Vue 3:

// 全局注册
import { createApp } from 'vue'
const app = createApp({})
app.component('MyComponent', {
  // 选项
})

// 局部注册(相同)
export default {
  components: {
    MyComponent
  }
}

7.2 Props

Vue 2 & Vue 3(相同):

<!-- 子组件 -->
<script>
export default {
  props: ['title', 'count'],
  // 或带验证
  props: {
    title: String,
    count: {
      type: Number,
      required: true,
      default: 0
    }
  }
}
</script>

<!-- 父组件 -->
<template>
  <Child title="标题" :count="10" />
</template>

Vue 3(Composition API):

<script setup>
const props = defineProps({
  title: String,
  count: {
    type: Number,
    required: true,
    default: 0
  }
})
</script>

7.3 Emit

Vue 2 & Vue 3(Options API):

<!-- 子组件 -->
<script>
export default {
  methods: {
    handleClick() {
      this.$emit('update', { id: 1, value: 'new' })
    }
  }
}
</script>

<!-- 父组件 -->
<template>
  <Child @update="handleUpdate" />
</template>

Vue 3(Composition API):

<script setup>
const emit = defineEmits(['update', 'delete'])

const handleClick = () => {
  emit('update', { id: 1, value: 'new' })
}
</script>

7.4 v-model 组件

Vue 2:

<!-- 子组件 -->
<template>
  <input :value="value" @input="$emit('input', $event.target.value)" />
</template>

<script>
export default {
  props: ['value'],
  model: {
    prop: 'value',
    event: 'input'
  }
}
</script>

Vue 3:

<!-- 子组件 -->
<template>
  <input :value="modelValue" @input="updateValue" />
</template>

<script setup>
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])

const updateValue = (e) => {
  emit('update:modelValue', e.target.value)
}
</script>

<!-- 父组件 -->
<CustomInput v-model="text" />

7.5 插槽(Slots)

Vue 2 & Vue 3(相同):

<!-- 子组件 -->
<template>
  <!-- 默认插槽 -->
  <slot>默认内容</slot>
  
  <!-- 具名插槽 -->
  <header><slot name="header"></slot></header>
  <footer><slot name="footer"></slot></footer>
  
  <!-- 作用域插槽 -->
  <slot name="item" :data="item" :index="index"></slot>
</template>

<!-- 父组件 -->
<template>
  <Child>
    <template #default>默认内容</template>
    <template #header>头部</template>
    <template #item="{ data, index }">
      {{ index }}: {{ data.name }}
    </template>
  </Child>
</template>

八、组件通信

8.1 父子通信

// 父传子:Props
// 子传父:$emit

// 父组件
<Child :data="data" @update="handleUpdate" />

// 子组件
props: ['data']
this.$emit('update', newData)

8.2 兄弟组件通信

Vue 2:事件总线

// bus.js
import Vue from 'vue'
export default new Vue()

// 组件 A
import bus from './bus'
bus.$emit('event', data)

// 组件 B
import bus from './bus'
bus.$on('event', (data) => {
  console.log(data)
})

Vue 3:mitt 或自定义事件总线

// 使用 mitt
import mitt from 'mitt'
const emitter = mitt()

emitter.emit('event', data)
emitter.on('event', (data) => {
  console.log(data)
})

8.3 provide/inject

Vue 2:

// 祖先组件
export default {
  provide() {
    return {
      theme: 'dark'
    }
  }
}

// 后代组件
export default {
  inject: ['theme']
}

Vue 3:

// 祖先组件
import { provide } from 'vue'
export default {
  setup() {
    provide('theme', 'dark')
  }
}

// 后代组件
import { inject } from 'vue'
export default {
  setup() {
    const theme = inject('theme', 'light') // 默认值
    return { theme }
  }
}

九、路由(Vue Router)

9.1 配置和使用

路由配置:

// Vue 2
import VueRouter from 'vue-router'
Vue.use(VueRouter)
export default new VueRouter({ mode: 'history', routes })

// Vue 3
import { createRouter, createWebHistory } from 'vue-router'
export default createRouter({ history: createWebHistory(), routes })

// 路由定义
const routes = [
  { path: '/', name: 'Home', component: Home },
  { path: '/user/:id', name: 'User', component: User },
  { path: '/about', name: 'About', component: () => import('@/views/About.vue') }
]

模板中使用:

<template>
  <router-link to="/">首页</router-link>
  <router-link :to="{ name: 'About' }">关于</router-link>
  <router-view />
</template>

编程式导航:

// 基本导航
this.$router.push('/about')
this.$router.push({ name: 'About' })
this.$router.replace('/about')  // 替换历史记录
this.$router.go(-1)            // 后退

// 路径参数(params)
this.$router.push('/user/123')
this.$router.push({ name: 'User', params: { id: 123 } })
this.$route.params.id  // 接收:123

// 查询参数(query)
this.$router.push('/detail?id=123&name=zhangsan')
this.$router.push({ path: '/detail', query: { id: 123, name: 'zhangsan' } })
this.$route.query.id    // 接收:123
this.$route.query.name  // 接收:'zhangsan'

Vue 3 Composition API:

<script setup>
import { useRouter, useRoute } from 'vue-router'

const router = useRouter()
const route = useRoute()

router.push({ name: 'User', params: { id: 123 } })
router.push({ path: '/detail', query: { id: 123 } })

const userId = route.params.id
const queryId = route.query.id
</script>

注意事项:

  • params 必须使用 name,不能使用 path
  • query 可以使用 pathname
  • params 在 URL 中不显示(除非在路由配置中定义)
  • query 会显示在 URL 中

十、状态管理(Vuex / Pinia)

10.1 Vuex(Vue 2 & Vue 3)

// store/index.js
import Vuex from 'vuex'
import Vue from 'vue' // Vue 2
// import { createStore } from 'vuex' // Vue 3

Vue.use(Vuex) // Vue 2

export default new Vuex.Store({
  // state:存储状态数据
  state: {
    count: 0
  },
  
  // mutations:同步修改 state(唯一方式)
  mutations: {
    increment(state) {
      state.count++
    }
  },
  
  // actions:异步操作,通过 commit 调用 mutations
  actions: {
    incrementAsync({ commit }) {
      setTimeout(() => {
        commit('increment')  // 调用 mutation
      }, 1000)
    }
  },
  
  // getters:计算属性,类似 computed
  getters: {
    doubleCount(state) {
      return state.count * 2
    }
  }
})

// 在组件中使用
// this.$store.state.count          // 访问 state
// this.$store.commit('increment')  // 调用 mutation
// this.$store.dispatch('incrementAsync')  // 调用 action
// this.$store.getters.doubleCount  // 访问 getter

10.2 Pinia(Vue 3 推荐)

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

export const useCounterStore = defineStore('counter', {
  // state:状态数据(必须是函数)
  state: () => ({
    count: 0
  }),
  
  // getters:计算属性
  getters: {
    doubleCount: (state) => state.count * 2
  },
  
  // actions:方法(可以是同步或异步)
  actions: {
    increment() {
      this.count++  // 直接修改 state
    },
    async fetchData() {
      // 异步操作
      const data = await api.getData()
      this.count = data.count
    }
  }
})

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

// 访问 state
counter.count

// 调用 action
counter.increment()

// 访问 getter
counter.doubleCount

// 重置 store
counter.$reset()

十一、常用指令和 API

11.1 指令

<template>
  <!-- v-text -->
  <div v-text="message"></div>
  
  <!-- v-html -->
  <div v-html="rawHtml"></div>
  
  <!-- v-cloak:防止闪烁 -->
  <div v-cloak>{{ message }}</div>
  
  <!-- v-once:只渲染一次 -->
  <div v-once>{{ message }}</div>
  
  <!-- v-pre:跳过编译 -->
  <div v-pre>{{ message }}</div>
</template>

11.2 实例属性

Vue 2:

this.$data      // 数据
this.$props     // Props
this.$el        // DOM 元素
this.$options   // 选项
this.$parent    // 父实例
this.$root      // 根实例
this.$children  // 子实例
this.$refs      // 引用
this.$router    // 路由
this.$route     // 当前路由
this.$store     // Vuex store

Vue 3:

// 大部分相同,但 $children 已移除
// 使用 $refs 访问子组件

十二、性能优化

12.1 列表渲染优化

<template>
  <!-- 使用 key -->
  <div v-for="item in items" :key="item.id">
    {{ item.name }}
  </div>
  
  <!-- 虚拟滚动(大数据) -->
  <virtual-list :data="largeList" />
</template>

12.2 组件懒加载

// 路由懒加载
const Home = () => import('@/views/Home.vue')

// 组件懒加载
const AsyncComponent = () => import('./AsyncComponent.vue')

12.3 计算属性缓存

// ✅ 使用计算属性(有缓存)
computed: {
  filteredList() {
    return this.list.filter(item => item.active)
  }
}

// ❌ 避免在模板中使用方法(无缓存)
methods: {
  filterList() {
    return this.list.filter(item => item.active)
  }
}

12.4 v-show vs v-if

<template>
  <!-- v-show:适合频繁切换 -->
  <div v-show="isVisible">内容</div>
  
  <!-- v-if:适合条件很少改变 -->
  <div v-if="isVisible">内容</div>
</template>

十三、Vue 2 到 Vue 3 迁移

13.1 主要变化

变化Vue 2Vue 3
创建应用new Vue()createApp()
全局 APIVue.component()app.component()
过滤器✅ 支持❌ 已移除
事件 API$on, $off❌ 已移除
v-modelvalue + inputmodelValue + update:modelValue
生命周期beforeDestroybeforeUnmount
响应式Object.definePropertyProxy

13.2 迁移步骤

  1. 升级依赖
npm install vue@3 vue-router@4 vuex@4
  1. 更新入口文件
// Vue 2
import Vue from 'vue'
new Vue({ ... }).$mount('#app')

// Vue 3
import { createApp } from 'vue'
createApp({ ... }).mount('#app')
  1. 更新组件语法
  • 使用 Composition API(可选)
  • 更新生命周期钩子名称
  • 移除过滤器,使用计算属性或方法

十四、最佳实践

14.1 组件设计

<!-- ✅ 单一职责 -->
<template>
  <UserCard :user="user" />
</template>

<!-- ✅ 可复用 -->
<template>
  <Button :type="type" @click="handleClick">
    <slot />
  </Button>
</template>

14.2 代码组织

<script>
export default {
  name: 'ComponentName',
  components: {},
  props: {},
  data() {},
  computed: {},
  watch: {},
  methods: {},
  lifecycle hooks...
}
</script>

14.3 命名规范

// 组件名:PascalCase
MyComponent.vue

// Props:camelCase
userName, isVisible

// 事件名:kebab-case
@user-updated, @item-deleted

// 方法名:camelCase
handleClick, fetchData

十五、推荐资源

官方文档:

学习资源:


十六、总结

Vue 核心要点:

响应式数据 + 组件化 + 指令系统 + 生态工具 = 高效前端开发

版本选择建议:

  • 新项目:推荐 Vue 3(性能更好,生态完善)
  • 现有项目:Vue 2 稳定,可逐步迁移

核心心法:

Vue 2 和 Vue 3 核心思想相同,主要是 API 差异。 掌握响应式原理和组件化思想是关键。


📝 文档信息

  • 作者: 阿鑫
  • 更新日期: 2026.1