阅读视图

发现新文章,点击刷新页面。

Vue2 与 Vue3 超全基础知识点汇总

本文涵盖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/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 汇总

  1. $on / $off / $once(EventBus 废弃)
  2. filter 过滤器
  3. mixin 混入
  4. $children / $destroy
  5. 旧版插槽语法 slot / slot-scope
  6. .sync 修饰符

19. 新手常见问题与注意事项

  1. Vue3 ref 修改变量必须加 .value,模板中不用
  2. v-for 必须加唯一 key,不要用 index
  3. v-if 和 v-for 不要同标签使用
  4. Vue2 对象 / 数组修改用 $set,Vue3 直接修改
  5. 计算属性有缓存,methods 无缓存
  6. 组件名要大驼峰,避免和 HTML 标签冲突

文末总结

  1. Vue2 以选项式 API为主,适合小型项目,响应式有缺陷;
  2. Vue3 以组合式 API为主,适合中大型项目,响应式完美,TS 友好;
  3. 新手优先学 Vue3 + Vite + Pinia,这是未来主流技术栈。
❌