目录
一、VUE2与VUE3的核心区别
1.全局状态管理
2.指令
a). v-model
3.组件引用
4.API调用方式
二、VUE3
1.全局状态管理
2.指令
a). v-model
3.父子组件传值
a).defineProps父传子(参数)
b).defineEmits子传父(事件)
4.ref、reactive、watch
ref作用
reactive作用
watch作用
5.API
a).h()渲染函数
一、VUE2与VUE3的核心区别
1.全局状态管理
state:全局变量(数据)
actions:全局方法(函数)→全局方法就写这里Pinia
getters:全局计算属性
| 特性 | Vue2 Vue.prototype | Pinia actions |
|---|---|---|
| 全局调用 | this.$xxx | store.xxx() |
| 响应式 | 需手动赋值 + nextTick | 自动响应,一改全更新 |
| 维护性 | 分散、混乱 | 集中在 store,清晰 |
| 异步 | 麻烦 | 原生支持 async/await |
2.指令
a). v-model
Vue 2 vs Vue 3 的区别
| 特性 | Vue 2 | Vue 3 |
|---|---|---|
| 默认 prop 名 | value | modelValue |
| 默认事件名 | input/change | update:modelValue |
| 多个 v-model | ❌ 不支持 | ✅ 支持 |
| 自定义修饰符 | ⚠️ 有限支持 | ✅ 完整支持 |
3.组件引用
| 注册方式 | Vue2 (选项式) | Vue3 (组合式 / <script setup>) |
|---|---|---|
| 全局注册 | Vue.component() | app.component() |
| 局部注册 | components: { 子组件 } | 无需注册,直接导入即用 |
| 自动导入 | 需插件 / 手动 | 支持unplugin-auto-import自动导入组件 |
| 入口文件 | main.js 用new Vue() | main.js 用createApp() |
| 单文件组件 | 必须写components选项 | 直接导入就可以用,最简洁 |
4.API调用方式
选项式 API(Vue2 默认):按功能类型拆分代码(data、methods、computed...)
组合式 API(Vue3 默认):按业务逻辑拆分代码(把相关的变量、方法放一起)
| 选项式 API(VUE2) | 组合式 API(VUE3<script setup>) | |
|---|---|---|
| 上手难度 | 简单,适合新手 | 稍难,但更强大 |
| 代码结构 | 分散,逻辑跳来跳去 | 聚合,清晰整洁 |
| 复用逻辑 | mixin(有缺陷) | 自定义 hook(优秀) |
| 大型项目 | 维护困难 | 维护轻松 |
| TS 支持 | 差 | 极好 |
| 代码体积 | 较大 | 更小,利于 TreeShaking |
二、VUE3
1.全局状态管理
在 Pinia 里,全局方法就是写在actions里的函数,所有组件都能调用,而且可以改 state、可以异步、可以互相调用Pinia,相比vue2更加的清晰功能上也更加全面。
state:全局变量(数据)
actions:全局方法(函数)→你要的全局方法就写这里Pinia
getters:全局计算属性
示例
import { defineStore } from 'pinia' export const useSysStore = defineStore('sys', { // 全局变量 state: () => ({ sysname: '银行对账系统', }), // 全局方法(写在这里!) actions: { // 同步全局方法 setSysName(model) { }, // 异步全局方法(例如:请求后端再改名字) async fetchSysName() { const res = await fetch('/api/sysname') const data = await res.json() this.sysname = data.name }, // 方法里调用另一个方法 resetAndSet(model) { this.$reset() // 重置state this.setSysName(model) } } })2.指令
a). v-model
Vue 3 允许通过参数绑定多个 v-model:
内置修饰符
| 修饰符 | 作用 | 适用场景 |
|---|---|---|
.lazy | 改为change事件触发 | 减少频繁更新 |
.number | 自动转为数字 | 数字输入 |
.trim | 去除首尾空格 | 文本输入 |
自定义修饰符(Vue 3)
父组件使用:
<template> <MyComponent v-model.capitalize="message" /> </template>子组件接收修饰符:
<script setup lang="ts"> interface Props { modelValue: string modelModifiers?: { capitalize?: boolean } } const props = defineProps<Props>() const emit = defineEmits<{ (e: 'update:modelValue', value: string): void }>() watchEffect(() => { if (props.modelModifiers?.capitalize) { emit('update:modelValue', props.modelValue.toUpperCase()) } }) </script>3.父子组件传值
a).defineProps父传子(参数)
Vue 组件是独立封闭的。子组件不能直接用父组件里的变量。想让子组件拿到父组件的数据,必须通过 props 传递,相当于父传子的数据通道。
核心规则
父 → 子 单向传递(子不能改 props)
子组件用 defineProps 接收
接收后可以直接在模板 / JS 里使用
父组件数据变了,子组件会自动更新(响应式)
b).defineEmits子传父(事件)
子组件不能直接改父组件的数据,必须发一个事件,让父组件接收。
// 子组件 <script setup> // 1. 定义要发送的事件名 const emit = defineEmits(['sendMsg']) function sendToParent() { // 2. 发送事件 + 数据 emit('sendMsg', '我是子组件发来的消息') } </script> <template> <button @click="sendToParent">点我发给父组件</button> </template>父组件监听子组件发出的事件,就能拿到值。
<script setup> function getMsg(data) { console.log('收到子组件消息:', data) } </script> <template> <!-- 监听子组件的 sendMsg 事件 --> <Child @sendMsg="getMsg" /> </template>4.ref、reactive、watch
ref:用来定义简单类型数据(数字、字符串、布尔)
reactive:用来定义复杂类型数据(对象、数组)
ref作用
监听简单数据类型的响应式:数字、字符串、布尔值
<script setup> import { ref } from 'vue' // 定义响应式变量 const count = ref(0) const name = ref('张三') const isShow = ref(true) </script>使用规则:
模板里不用 .value
JS 里必须用 .value
<template> <div>{{ count }}</div> <!-- 不用 .value --> </template> <script setup> console.log(count.value) // JS 里必须 .value count.value = 100 </script>reactive作用
监听复杂数据类型的响应式:对象、数组
<script setup> import { reactive } from 'vue' // 对象 const user = reactive({ name: '李四', age: 20 }) // 数组 const list = reactive([1,2,3]) </script>使用规则:
永远不用 .value
直接用属性即可
<template> <div>{{ user.name }}</div> </template> <script setup> user.name = '王五' </script>常见问题:reactive 不能直接重新赋值
const user = reactive({ name: '张三' }) // ❌ 错误,会丢失响应式 user = { name: '李四' } ✅ 正确: // 改属性 user.name = '李四' // 或用 Object.assign Object.assign(user, { name: '李四' })对比表
| 特性 | ref | reactive |
|---|---|---|
| 支持类型 | 简单类型 + 对象 / 数组 | 只能 对象 / 数组 |
| JS 访问 | 必须 .value | 不用 .value |
| 模板访问 | 不用 .value | 不用 .value |
| 重新赋值 | 可以 | 不推荐直接赋值 |
| 使用场景 | 单个变量 | 对象、数组 |
5.API
a).h()渲染函数
创建虚拟 DOM 节点 (vnode)。
详细信息
第一个参数既可以是一个字符串 (用于原生元素) 也可以是一个 Vue 组件定义。第二个参数是要传递的 prop,第三个参数是子节点。
当创建一个组件的 vnode 时,子节点必须以插槽函数进行传递。如果组件只有默认槽,可以使用单个插槽函数进行传递。否则,必须以插槽函数的对象形式来传递。
为了方便阅读,当子节点不是插槽对象时,可以省略 prop 参数。