本文涵盖Vue2/Vue3 所有核心基础 API,每个知识点都配完整可运行代码 + 逐行注释,0 基础也能看懂。全文从入门到实战,对比两代 Vue 差异。
1. Vue 基础认知
1.1 核心定义
Vue 是一套用于构建用户界面的渐进式 JavaScript 框架,核心是数据驱动视图,数据变→视图自动变,无需手动操作 DOM。
1.2 Vue2 vs Vue3 核心区别
| 对比项 |
Vue2 |
Vue3 |
| 响应式原理 |
Object.defineProperty |
ES6 Proxy(无监听缺陷) |
| 代码风格 |
选项式 API(Options API) |
组合式 API(Composition API)+ 兼容选项式 |
| TS 支持 |
差,需手动配置 |
原生 TS,类型推导完美 |
| 构建工具 |
Vue-CLI(Webpack) |
Vite(极速启动) |
| 体积 |
全量打包,体积大 |
按需引入,Tree-Shaking 优化 |
| 性能 |
普通 |
渲染性能提升 55%,内存减少 33% |
2. 项目创建与目录结构
2.1 Vue2 项目创建
bash 运行
# 1. 全局安装Vue脚手架
npm install -g @vue/cli
# 2. 创建项目
vue create vue2-project
# 3. 运行项目
cd vue2-project
npm run serve
2.2 Vue3 项目创建(推荐 Vite)
bash 运行
# 1. Vite创建Vue3项目
npm create vite@latest vue3-project -- --template vue
# 2. 安装依赖
cd vue3-project
npm install
# 3. 运行项目
npm run dev
3. 入口文件 main.js 完整写法
3.1 Vue2 入口文件
javascript 运行
// 引入Vue核心库
import Vue from 'vue'
// 引入根组件
import App from './App.vue'
// 关闭生产环境提示
Vue.config.productionTip = false
// 创建Vue实例,挂载根组件到#app
new Vue({
// 渲染函数
render: h => h(App)
}).$mount('#app') // 挂载到public/index.html的#app节点
3.2 Vue3 入口文件
javascript 运行
// 引入createApp创建应用实例
import { createApp } from 'vue'
// 引入根组件
import App from './App.vue'
// 引入样式
import './style.css'
// 1. 创建应用实例
const app = createApp(App)
// 2. 挂载到DOM节点
app.mount('#app')
// 拓展:全局配置(Vue3无全局污染)
// app.config.globalProperties.$msg = '全局变量'
4. 模板核心语法(全指令详解)
Vue 模板语法基于 HTML,所有指令以 v- 开头,数据变视图自动更新。
4.1 文本插值 {{}}
<!-- Vue2 和 Vue3 模板插值用法完全一致 -->
<template>
<div>
<!-- 直接渲染变量 -->
<h1>{{ msg }}</h1>
<!-- 渲染表达式 -->
<p>{{ num + 1 }}</p>
<p>{{ isShow ? '显示' : '隐藏' }}</p>
</div>
</template>
<!-- Vue2 -->
<script>
export default {
data() {
return {
msg: 'Hello Vue2',
num: 10,
isShow: true
}
}
}
</script>
<!-- Vue3 -->
<script setup>
import { ref } from 'vue'
const msg = ref('Hello Vue3')
const num = ref(10)
const isShow = ref(true)
</script>
4.2 v-html 渲染 HTML 标签
{{}} 会转义标签,v-html 可解析原生 HTML
<template>
<div v-html="htmlStr"></div>
</template>
<!-- Vue2 -->
<script>
export default {
data() {
return { htmlStr: '<span style="color:red">红色文字</span>' }
}
}
</script>
<!-- Vue3 -->
<script setup>
import { ref } from 'vue'
const htmlStr = ref('<span style="color:red">红色文字</span>')
</script>
⚠️ 安全警告:仅在信任的内容上使用 v-html,防止 XSS 攻击!
4.3 v-bind 绑定属性(简写:)
动态绑定标签属性(src、class、style、disabled 等)
<template>
<!-- 完整写法 -->
<img v-bind:src="imgUrl" />
<!-- 简写: (最常用) -->
<img :src="imgUrl" />
<!-- 绑定class -->
<div :class="{ active: isActive }">class绑定</div>
</template>
<!-- Vue2 -->
<script>
export default {
data() {
return {
imgUrl: 'https://xxx.jpg',
isActive: true
}
}
}
</script>
4.4 v-on 绑定事件(简写 @)
绑定点击、输入、鼠标等事件
<template>
<!-- 完整写法 -->
<button v-on:click="handleClick">点击</button>
<!-- 简写@ (最常用) -->
<button @click="handleClick">点击</button>
<!-- 传参 -->
<button @click="handleClickParams(10)">传参点击</button>
</template>
<!-- Vue2 -->
<script>
export default {
methods: {
handleClick() { alert('Vue2点击事件') },
handleClickParams(num) { alert('参数:' + num) }
}
}
</script>
4.5 v-model 双向绑定(表单专用)
表单元素(input/textarea/select)数据双向同步
vue2
<template>
<input v-model="inputVal" placeholder="请输入" />
<p>输入内容:{{ inputVal }}</p>
</template>
<!-- Vue2 -->
<script>
export default {
data() { return { inputVal: '' } }
}
</script>
vue3 统一语法,支持多 v-model,废弃 .sync
<!-- 父组件 -->
<Child v-model:msg="msg" v-model:age="age" />
<!-- 子组件 -->
<script setup>
const props = defineProps(['msg', 'age'])
const emit = defineEmits(['update:msg', 'update:age'])
</script>
4.6 v-for 列表渲染(必须加 key)
循环渲染数组 / 对象,key 必须唯一,不能用 index
<template>
<ul>
<li v-for="item in list" :key="item.id">{{ item.name }}</li>
</ul>
</template>
<!-- Vue2 -->
<script>
export default {
data() {
return { list: [{id:1,name:'苹果'},{id:2,name:'香蕉'}] }
}
}
</script>
4.7 v-if /v-else/v-else-if 条件渲染
控制元素创建 / 销毁,切换开销大
<template>
<div v-if="score >= 90">优秀</div>
<div v-else-if="score >= 60">及格</div>
<div v-else">不及格</div>
</template>
4.8 v-show 条件显示
控制元素显示 / 隐藏(display:none),切换开销小
<template>
<div v-show="isShow">v-show显示内容</div>
</template>
4.9 其他指令
-
v-once:只渲染一次,后续数据更新不重新渲染
-
v-pre:跳过编译,直接显示原始内容
-
v-cloak:解决插值表达式闪烁问题
5. 响应式数据 API 全解(最核心)
响应式:数据改变 → 视图自动刷新,无需操作 DOM
5.1 Vue2 响应式 API
5.1.1 data 定义响应式数据
data 必须是函数,返回对象,防止组件复用数据污染
<script>
export default {
// data是函数,返回对象
data() {
return {
// 基本数据类型
msg: 'Vue2',
num: 0,
// 引用数据类型
user: { name: '张三', age: 18 },
list: [1,2,3]
}
}
}
</script>
5.1.2 Vue2 响应式缺陷 & 修复 API
Vue2 用 Object.defineProperty,无法监听数组下标修改、对象新增属性
<script>
export default {
data() { return { user: {}, list: [1,2] } },
mounted() {
// 1. 对象新增属性 → 视图不更新
this.user.name = '张三' // 无效
// 修复:this.$set
this.$set(this.user, 'name', '张三')
// 2. 数组下标修改 → 视图不更新
this.list[0] = 100 // 无效
// 修复:this.$set
this.$set(this.list, 0, 100)
// 3. 删除对象属性 → 视图不更新
// 修复:this.$delete
this.$delete(this.user, 'name')
}
}
</script>
5.2 Vue3 响应式 API(组合式)
Vue3 用 Proxy,无任何响应式缺陷,所有操作都能监听
5.2.1 ref 定义基本数据类型
用于:字符串、数字、布尔、null、undefined
<script setup>
// 1. 引入ref
import { ref } from 'vue'
// 2. 定义响应式数据
const msg = ref('Hello Vue3') // 字符串
const num = ref(0) // 数字
const isShow = ref(true) // 布尔
// 3. JS中修改值必须加 .value
const changeMsg = () => {
msg.value = '修改后的Vue3'
num.value++
}
</script>
<template>
<!-- 模板中自动解包,无需.value -->
<p>{{ msg }}</p>
<p>{{ num }}</p>
<button @click="changeMsg">修改数据</button>
</template>
5.2.2 reactive 定义引用数据类型
用于:对象、数组、Map、Set
<script setup>
import { reactive } from 'vue'
// 定义对象
const user = reactive({ name: '李四', age: 20 })
// 定义数组
const list = reactive(['苹果', '香蕉'])
// 修改数据:直接修改,无需.value
const updateUser = () => {
user.age = 21 // 直接改
list[0] = '葡萄' // 直接改数组下标,无缺陷
}
</script>
5.2.3 toRefs 解构 reactive 数据
reactive 解构后会丢失响应式,用 toRefs 修复
<script setup>
import { reactive, toRefs } from 'vue'
const user = reactive({ name: '王五', age: 25 })
// 错误:解构后无响应式
// const { name, age } = user
// 正确:toRefs 保持响应式
const { name, age } = toRefs(user)
// 修改数据
const changeAge = () => {
age.value = 26
}
</script>
5.2.4 toRef 单独抽取一个属性
<script setup>
import { reactive, toRef } from 'vue'
const user = reactive({ name: '赵六' })
// 抽取单个属性
const name = toRef(user, 'name')
</script>
5.2.5 其他响应式 API
-
unref:如果是 ref 返回.value,否则返回本身
-
shallowRef:浅响应式,只监听.value 修改
-
shallowReactive:浅响应式,只监听第一层属性
6. 方法(methods)与事件处理
6.1 Vue2 定义方法
所有方法放在 methods 选项中
<template>
<button @click="add">点击+1</button>
<p>数字:{{ num }}</p>
</template>
<script>
export default {
data() { return { num: 0 } },
// 方法存放位置
methods: {
add() {
// 通过this访问data数据
this.num++
}
}
}
</script>
6.2 Vue3 定义方法
直接在 <script setup> 中定义函数,模板直接用
<template>
<button @click="add">点击+1</button>
<p>数字:{{ num }}</p>
</template>
<script setup>
import { ref } from 'vue'
const num = ref(0)
// 直接定义函数
const add = () => {
num.value++
}
</script>
6.3 事件修饰符
<!-- 阻止冒泡 -->
<button @click.stop="handle">.stop</button>
<!-- 阻止默认行为 -->
<a @click.prevent="handle">.prevent</a>
<!-- 只触发一次 -->
<button @click.once="handle">.once</button>
7. 生命周期钩子完整对比 + 使用
生命周期:Vue 实例从创建→挂载→更新→销毁的全过程
7.1 完整生命周期对应表
| Vue2 钩子 |
Vue3 钩子 |
执行时机 |
| beforeCreate |
setup |
创建前(无 this) |
| created |
setup |
创建后(可访问数据) |
| beforeMount |
onBeforeMount |
挂载前 |
| mounted |
onMounted |
挂载完成(操作 DOM、发请求) |
| beforeUpdate |
onBeforeUpdate |
更新前 |
| updated |
onUpdated |
更新完成 |
| beforeDestroy |
onBeforeUnmount |
销毁前 |
| destroyed |
onUnmounted |
销毁完成 |
7.2 Vue2 生命周期使用
<script>
export default {
data() { return { msg: 'Vue2生命周期' } },
// 挂载完成,最常用
mounted() {
console.log('DOM渲染完成,可发请求')
},
// 销毁前
beforeDestroy() {
console.log('组件销毁,清除定时器')
}
}
</script>
7.3 Vue3 生命周期使用
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const msg = ref('Vue3生命周期')
// 挂载完成
onMounted(() => {
console.log('DOM渲染完成')
})
// 组件销毁
onUnmounted(() => {
console.log('组件销毁')
})
</script>
8. 计算属性 computed(缓存特性)
8.1 作用
处理复杂逻辑,有缓存,依赖数据不变时不会重新计算,比 methods 性能高
8.2 Vue2 computed
<template>
<p>全名:{{ fullName }}</p>
</template>
<script>
export default {
data() {
return { firstName: '张', lastName: '三' }
},
// 计算属性
computed: {
// 只读计算属性
fullName() {
return this.firstName + this.lastName
},
// 读写计算属性(get+set)
fullName2: {
get() { return this.firstName + this.lastName },
set(val) {
const arr = val.split(' ')
this.firstName = arr[0]
this.lastName = arr[1]
}
}
}
}
</script>
8.3 Vue3 computed
<script setup>
import { ref, computed } from 'vue'
const firstName = ref('李')
const lastName = ref('四')
// 只读计算属性
const fullName = computed(() => {
return firstName.value + lastName.value
})
// 读写计算属性
const fullName2 = computed({
get() { return firstName.value + lastName.value },
set(val) {
const arr = val.split(' ')
firstName.value = arr[0]
lastName.value = arr[1]
}
})
</script>
9. 侦听器 watch /watchEffect(监听数据变化)
9.1 watch 监听指定数据(Vue2)
<script>
export default {
data() { return { num: 0, user: { age: 18 } } },
watch: {
// 监听基本类型
num(newVal, oldVal) {
console.log('新值:', newVal, '旧值:', oldVal)
},
// 深度监听对象(必须加deep:true)
user: {
handler(newVal) { console.log('user变化:', newVal) },
deep: true,
immediate: true // 立即执行一次
}
}
}
</script>
9.2 watch 监听指定数据(Vue3)
<script setup>
import { ref, reactive, watch } from 'vue'
const num = ref(0)
const user = reactive({ age: 18 })
// 监听基本类型
watch(num, (newVal, oldVal) => {
console.log(newVal, oldVal)
})
// 深度监听对象
watch(user, (newVal) => {
console.log(newVal)
}, { deep: true, immediate: true })
</script>
9.3 watchEffect 自动监听(Vue3 专属)
无需指定依赖,自动收集,代码更简洁
<script setup>
import { ref, watchEffect } from 'vue'
const num = ref(0)
// 只要num变化,自动执行
watchEffect(() => {
console.log('num变化:', num.value)
})
</script>
10. 组件基础定义与使用
组件:可复用的 Vue 实例,一个组件就是一个.vue 文件
10.1 Vue2 组件使用
<!-- 父组件 App.vue -->
<template>
<div>
<!-- 使用子组件 -->
<Child />
</div>
</template>
<script>
// 1. 引入子组件
import Child from './components/Child.vue'
export default {
// 2. 注册组件
components: { Child }
}
</script>
<!-- 子组件 Child.vue -->
<template>
<div>我是子组件</div>
</template>
10.2 Vue3 组件使用
<script setup> 中引入即注册,无需手动注册
<!-- 父组件 -->
<template>
<Child />
</template>
<script setup>
// 引入直接用,无需注册
import Child from './components/Child.vue'
</script>
11. 组件通信 8 种方式(全场景)
11.1 父传子 props(最常用)
Vue2 父传子
<!-- 父组件 -->
<Child :msg="父组件数据" :user="user" />
<script>
import Child from './Child.vue'
export default {
components: { Child },
data() { return { msg: '父组件传给子组件', user: { name: '父' } } }
}
</script>
<!-- 子组件 -->
<script>
export default {
// 接收父组件数据
props: {
msg: String,
user: Object
}
}
</script>
Vue3 父传子
<!-- 父组件 -->
<Child :msg="父组件数据" />
<script setup>
import Child from './Child.vue'
const msg = ref('父组件数据')
</script>
<!-- 子组件 -->
<script setup>
import { defineProps } from 'vue'
// 定义props,接收数据
const props = defineProps({
msg: {
type: String,
default: ''
}
})
// 模板中直接用{{ msg }}
</script>
11.2 子传父 $emit /defineEmits
Vue2 子传父
<!-- 子组件 -->
<button @click="sendToParent">发送给父组件</button>
<script>
export default {
methods: {
sendToParent() {
// 触发自定义事件,传参
this.$emit('sendMsg', '子组件数据')
}
}
}
</script>
<!-- 父组件 -->
<Child @sendMsg="handleReceive" />
<script>
export default {
methods: {
handleReceive(val) { console.log('接收子组件数据:', val) }
}
}
</script>
Vue3 子传父
<!-- 子组件 -->
<script setup>
import { defineEmits } from 'vue'
// 定义自定义事件
const emit = defineEmits(['sendMsg'])
const send = () => {
emit('sendMsg', 'Vue3子组件数据')
}
</script>
<!-- 父组件 -->
<Child @sendMsg="handleReceive" />
11.3 其他通信方式
1、兄弟组件通信:Vue2 → EventBus;Vue3 → mitt / Pinia
2、跨级组件通信:provide /inject
适用场景:多层嵌套组件(如祖父→父→孙→曾孙),无需逐层透传props,由祖先组件提供数据,后代组件直接注入使用。
Vue2 vs Vue3 核心差异
| 特性 |
Vue2 |
Vue3 |
| 响应式 |
默认非响应式,需手动用computed/ref包装 |
原生支持响应式,直接传递ref/reactive即可 |
| API 位置 |
选项式 API(provide/inject选项) |
组合式 API(setup中用provide/inject函数) |
| TS 支持 |
弱 |
强(类型自动推导) |
Vue2 示例
javascript 运行
// 祖先组件(App.vue)
export default {
provide() {
return {
// 传递响应式数据,必须用computed包装
appName: computed(() => this.appName),
userInfo: { name: '张三', age: 30 }
}
},
data() {
return {
appName: 'Vue2 应用'
}
}
}
// 后代组件(任意层级,如孙组件)
export default {
inject: ['appName', 'userInfo'],
mounted() {
console.log('注入的appName:', this.appName.value) // computed需.value
console.log('注入的userInfo:', this.userInfo)
}
}
Vue3 示例(组合式 API + <script setup>)
<!-- 祖先组件 App.vue -->
<script setup>
import { provide, ref, reactive } from 'vue'
// 响应式数据
const appName = ref('Vue3 应用')
const userInfo = reactive({ name: '张三', age: 30 })
// 提供数据,直接传递响应式变量
provide('appName', appName)
provide('userInfo', userInfo)
</script>
<!-- 后代组件(任意层级) -->
<script setup>
import { inject } from 'vue'
// 注入数据,第二个参数为默认值(可选)
const appName = inject('appName', '默认应用名')
const userInfo = inject('userInfo')
console.log('注入的appName:', appName.value) // ref需.value
console.log('注入的userInfo:', userInfo)
</script>
3、ref / $refs:父组件获取子组件实例
适用场景:父组件需要直接调用子组件的方法、访问子组件的 data,或操作子组件的 DOM 元素。
Vue2 vs Vue3 核心差异
表格
| 特性 |
Vue2 |
Vue3 |
| 获取实例 |
this.$refs.child |
选项式同 Vue2;组合式需在onMounted后通过ref获取 |
<script setup>支持 |
无此语法 |
子组件必须用defineExpose显式暴露属性 / 方法 |
| DOM 访问 |
this.$refs.dom |
同 Vue2,组合式需ref绑定 |
Vue2 示例
<!-- 子组件 Child.vue -->
<template>
<div>子组件</div>
</template>
<script>
export default {
data() {
return {
childMsg: '我是子组件数据'
}
},
methods: {
childMethod() {
console.log('子组件方法被调用')
return '子组件返回值'
}
}
}
</script>
<!-- 父组件 Parent.vue -->
<template>
<Child ref="childComp" />
<div ref="domBox">父组件DOM</div>
</template>
<script>
import Child from './Child.vue'
export default {
components: { Child },
mounted() {
// 获取子组件实例
const childInstance = this.$refs.childComp
console.log('子组件数据:', childInstance.childMsg)
// 调用子组件方法
const res = childInstance.childMethod()
console.log('子组件方法返回值:', res)
// 获取DOM元素
const dom = this.$refs.domBox
console.log('DOM元素:', dom)
}
}
</script>
Vue3 示例(<script setup>)
<!-- 子组件 Child.vue -->
<template>
<div>子组件</div>
</template>
<script setup>
import { ref } from 'vue'
const childMsg = ref('我是子组件数据')
const childMethod = () => {
console.log('子组件方法被调用')
return '子组件返回值'
}
// 【关键】<script setup>默认闭包,必须显式暴露给父组件!
defineExpose({
childMsg,
childMethod
})
</script>
<!-- 父组件 Parent.vue -->
<template>
<Child ref="childComp" />
<div ref="domBox">父组件DOM</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import Child from './Child.vue'
// 声明ref,绑定到子组件/DOM
const childComp = ref(null)
const domBox = ref(null)
onMounted(() => {
// 必须在onMounted后才能获取到实例/DOM!
console.log('子组件实例:', childComp.value)
console.log('子组件数据:', childComp.value.childMsg)
const res = childComp.value.childMethod()
console.log('子组件方法返回值:', res)
// 获取DOM
console.log('DOM元素:', domBox.value)
})
</script>
4、全局状态管理:Vuex(Vue2) / Pinia(Vue3)
适用场景:中大型项目,任意关系组件共享全局状态,需要统一管理状态读写、异步操作。
Vue2 方案:Vuex(Vue2 官方状态管理)
Vuex 核心概念:State(状态)、Mutations(同步修改)、Actions(异步操作)、Getters(计算属性)、Modules(模块化)。
javascript 运行
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0,
userInfo: null
},
mutations: {
// 同步修改state(唯一修改state的方式)
increment(state, payload = 1) {
state.count += payload
},
setUserInfo(state, user) {
state.userInfo = user
}
},
actions: {
// 异步操作,提交mutation
async fetchUserInfo({ commit }) {
const res = await fetch('/api/user')
const user = await res.json()
commit('setUserInfo', user)
}
},
getters: {
doubleCount: state => state.count * 2
}
})
// 组件中使用
export default {
computed: {
count() {
return this.$store.state.count
},
doubleCount() {
return this.$store.getters.doubleCount
}
},
methods: {
addCount() {
this.$store.commit('increment', 2) // 提交mutation
},
getUserInfo() {
this.$store.dispatch('fetchUserInfo') // 触发action
}
}
}
Vue3 方案:Pinia(Vue3 官方推荐,替代 Vuex)
Pinia 是 Vue3 的下一代状态管理,相比 Vuex:
- 去掉
Mutations,直接在actions中修改状态(同步 / 异步都支持)
- 自动模块化,无需手动注册
- 完美支持 TS,组合式 API 友好
- 体积仅~1KB,DevTools 支持更好
javascript 运行
// stores/counter.js
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0,
userInfo: null
}),
getters: {
doubleCount: (state) => state.count * 2
},
actions: {
// 同步/异步直接写,无需mutation
increment(payload = 1) {
this.count += payload
},
async fetchUserInfo() {
const res = await fetch('/api/user')
const user = await res.json()
this.userInfo = user
}
}
})
// 组件中使用(<script setup>)
<script setup>
import { useCounterStore } from '@/stores/counter'
import { storeToRefs } from 'pinia'
const counterStore = useCounterStore()
// 解构保持响应式(必须用storeToRefs)
const { count, doubleCount, userInfo } = storeToRefs(counterStore)
// 直接调用action
const addCount = () => counterStore.increment(2)
const getUserInfo = () => counterStore.fetchUserInfo()
</script>
5、parent/children:父子直接访问(不推荐)
12. 插槽 Slot(默认 / 具名 / 作用域)
插槽:父组件向子组件传递 HTML 结构
12.1 默认插槽
<!-- 子组件 -->
<slot>默认内容</slot>
<!-- 父组件 -->
<Child>我是插入的内容</Child>
12.2 具名插槽(多个插槽)
Vue2
<!-- 子组件 -->
<slot name="header"></slot>
<!-- 父组件 -->
<template slot="header">头部内容</template>
Vue3(v-slot 简写 #)
<!-- 子组件 -->
<slot name="header"></slot>
<!-- 父组件 -->
<template #header>头部内容</template>
12.3 作用域插槽(子传数据给插槽)
<!-- 子组件 -->
<slot :user="user"></slot>
<script setup>
const user = reactive({ name: '插槽数据' })
</script>
<!-- 父组件 -->
<template #default="scope">
{{ scope.user.name }}
</template>
13. 自定义指令 Directive
13.1 Vue2 自定义指令
javascript 运行
// 全局指令
Vue.directive('focus', {
inserted(el) { el.focus() }
})
// 局部指令
export default {
directives: {
focus: { inserted(el) { el.focus() } }
}
}
13.2 Vue3 自定义指令
javascript 运行
// 全局指令
app.directive('focus', {
mounted(el) { el.focus() }
})
// 局部指令
<script setup>
const vFocus = { mounted: (el) => el.focus() }
</script>
<template> <input v-focus /> </template>
14. 过滤器 Filter(Vue2 有 / Vue3 废弃)
Vue2 过滤器
<template>
<p>{{ msg | reverse }}</p>
</template>
<script>
export default {
data() { return { msg: 'abc' } },
filters: {
reverse(val) { return val.split('').reverse().join('') }
}
}
</script>
Vue3 替代方案
用计算属性或函数替代过滤器
<script setup>
import { ref, computed } from 'vue'
const msg = ref('abc')
const reverseMsg = computed(() => msg.value.split('').reverse().join(''))
</script>
15. 混入 Mixin(Vue2 有 / Vue3 废弃)
Vue2 用于复用代码,Vue3 用组合式函数替代
// mixin.js
export default {
data() { return { mixinMsg: 'mixin数据' } },
methods: { mixinFun() { console.log('mixin方法') } }
}
// 组件使用
import myMixin from './mixin.js'
export default { mixins: [myMixin] }
16. 路由 Vue-Router(完整配置 + 使用)
16.1 Vue2 + Vue-Router@3
javascript 运行
// router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
Vue.use(VueRouter)
const routes = [
{ path: '/', component: Home }
]
const router = new VueRouter({ routes })
export default router
// main.js 引入
import router from './router'
new Vue({ router }).$mount('#app')
16.2 Vue3 + Vue-Router@4
javascript 运行
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
const routes = [
{ path: '/', component: Home }
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
// 组件使用
<script setup>
import { useRouter, useRoute } from 'vue-router'
const router = useRouter() // 跳转
const route = useRoute() // 获取参数
// 跳转
const goHome = () => router.push('/')
</script>
17. Vue3 新增高级 API
17.1 Teleport 传送门
将组件渲染到指定 DOM,常用于弹窗
<teleport to="body">
<div class="modal">弹窗内容</div>
</teleport>
17.2 Suspense 异步组件
<Suspense>
<template #default>
<AsyncComponent />
</template>
<template #fallback>
<div>加载中...</div>
</template>
</Suspense>
17.3 defineComponent 类型推导
<script setup>
import { defineComponent } from 'vue'
const MyComponent = defineComponent({/*...*/})
</script>
18. Vue2 废弃 API 汇总
-
$on / $off / $once(EventBus 废弃)
-
filter 过滤器
-
mixin 混入
-
$children / $destroy
- 旧版插槽语法
slot / slot-scope
-
.sync 修饰符
19. 新手常见问题与注意事项
- Vue3 ref 修改变量必须加
.value,模板中不用
- v-for 必须加唯一 key,不要用 index
- v-if 和 v-for 不要同标签使用
- Vue2 对象 / 数组修改用 $set,Vue3 直接修改
- 计算属性有缓存,methods 无缓存
- 组件名要大驼峰,避免和 HTML 标签冲突
文末总结
- Vue2 以选项式 API为主,适合小型项目,响应式有缺陷;
- Vue3 以组合式 API为主,适合中大型项目,响应式完美,TS 友好;
- 新手优先学 Vue3 + Vite + Pinia,这是未来主流技术栈。