前端核心框架vue之(组件篇2/5)
写在前面的话,vue的组件开发,非常的重要,暂时不需要用到脚手架;反而使用脚手架可能让我们的注意力分散,主包认为现阶段要把注意力集中在代码逻辑上
📦 Vue 组件入门教程(主包建议用时20min-2h)
🧠 一、什么是 Vue 组件?(入门解释)
✅ 一句话解释:
组件就是“可以重复用的小网页模块”,像乐高积木,拼起来变成完整网页。
✅ 举例理解:
网页里常见重复部分:
- 用户卡片
- 点赞按钮
- 评论区域
👉 可以写成一个组件,一次写好,多处使用,改样式改一处就行。
🧱 二、一个组件长什么样?(结构图 + 类比讲解)
一个 .vue
文件通常有三块:
<template> 👈 页面结构(HTML)
<script> 👈 逻辑与数据(JS)
<style> 👈 样式外观(CSS)
部分 | 类比 | 功能 |
---|---|---|
<template> | 舞台布景 | 结构、展示什么内容 |
<script> | 脑袋 + 行为 | 数据、事件响应 |
<style> | 穿衣服 | 颜色、布局、外观 |
🔧 三、组件三部分怎么写?(拆解示例)
1️⃣ <template>
结构层
<template><div class="card"><h2>{{ title }}</h2><p>{{ content }}</p><button @click="like">点赞 {{ likes }}</button></div>
</template>
{{ title }}
:双大括号显示变量@click="like"
:点击时调用like()
方法
👉 类比 jQuery 的 $('#btn').click(...)
。
2️⃣ <script>
逻辑层
<script>
export default {name: 'MyCard',data() {return {title: '欢迎来到 Vue 组件',content: '这是一段组件的说明文字。',likes: 0}},methods: {like() {this.likes++}}
}
</script>
data()
:放变量methods
:放事件、动作this.likes++
:变量变化 Vue 自动刷新页面(响应式)
3️⃣ <style>
样式层
<style scoped>
.card {border: 1px solid #ccc;padding: 16px;border-radius: 8px;
}
</style>
scoped
表示样式只影响当前组件
🔄 四、组件使用流程(如何用)
✅ 组件文件 MyCard.vue
<template><div class="card"><h2>{{ title }}</h2><p>{{ content }}</p><button @click="like">点赞 {{ likes }}</button></div>
</template><script>
export default {name: 'MyCard',data() {return {title: '欢迎来到 Vue 组件',content: '这是一段组件的说明文字。',likes: 0}},methods: {like() {this.likes++}}
}
</script><style scoped>
.card {border: 1px solid #ccc;padding: 16px;border-radius: 8px;
}
</style>
✅ 在 App.vue 使用组件
<template><div><h1>我的首页</h1><MyCard /></div>
</template><script>
import MyCard from './components/MyCard.vue'export default {name: 'App',components: {MyCard}
}
</script>
📁 五、项目结构建议(脚手架的项目结构,目前了解一下即可)
src/
├── components/ 👈 放各种组件
│ └── MyCard.vue 👈 自定义组件
└── App.vue 👈 根组件,拼装页面
🧪 六、传统写法 vs 组件写法(案例对比)
🚫 传统 HTML 写法(重复 + 不好维护)
<!-- 第一张卡片 -->
<div class="user-card"><img src="avatar1.png" /><h2>Mike</h2><button>关注</button>
</div><!-- 第二张卡片 -->
<div class="user-card"><img src="avatar2.png" /><h2>李四</h2><button>关注</button>
</div><!-- 第三张卡片 -->
<div class="user-card"><img src="avatar3.png" /><h2>王五</h2><button>关注</button>
</div>
📌 问题:
- 写三次几乎一模一样的结构,浪费时间
- 想改样式,要改三处(容易漏)
- 没有逻辑(比如关注状态)不能复用
✅ Vue 组件封装写法(简洁 + 可复用)
UserCard.vue
(组件):
<template><div class="user-card"><img :src="avatar" /><h2>{{ name }}</h2><button @click="toggleFollow">{{ isFollowed ? '已关注' : '关注' }}</button></div>
</template><script>
export default {props: ['avatar', 'name'],data() {return {isFollowed: false}},methods: {toggleFollow() {this.isFollowed = !this.isFollowed}}
}
</script><style scoped>
.user-card {border: 1px solid #ddd;padding: 10px;text-align: center;
}
</style>
在页面中使用:
<UserCard avatar="avatar1.png" name="Mike" />
<UserCard avatar="avatar2.png" name="李四" />
<UserCard avatar="avatar3.png" name="王五" />
✅ 如果还没学 .vue
文件(脚手架),也能这样写(传统引入方式):
<script>
Vue.component('user-card', {props: ['avatar', 'name'],data() {return { isFollowed: false }},template: `<div class="user-card"><img :src="avatar" /><h2>{{ name }}</h2><button @click="isFollowed = !isFollowed">{{ isFollowed ? '已关注' : '关注' }}</button></div>`
});
</script>
🎯 为什么要用组件?
组件不是花哨,而是为了“把重复的代码变聪明”,未来项目越大越管用!
✅ 用组件,就像“写好一张卡片模版”:
以上案例中使用组件与不使用组件的好处如下:
对比 | 传统写法 | Vue 组件 |
---|---|---|
重复部分 | 手动写好几次 | 写一次,用无数次 |
逻辑和结构 | 混在一起,重复出错 | 封装在一个组件里 |
改样式 | 每一块都要改 | 组件里改一处就全都更新 |
数据传递 | 自己写很多手动逻辑 | 父传子/子传父都内置支持 |
页面越来越复杂 | 越写越乱,维护困难 | 拆成小组件,模块清晰 |
类比 | 一堆复制粘贴的纸条 | 做一个模具,反复打印卡片 |
🧑🏫 实习生记住一句:
Vue 组件 = 写一次、用多次、改一次、全部生效。
很多实习生都会卡住的关键点:“前端为什么能识别 template 和 .vue 文件?” —— 因为在浏览器里我们看不到 render()
和虚拟 DOM 的“真实过程”,这一切都是 Vue 帮我们“偷偷做了很多事”。
下面把这个本质过程讲明白👇
🧬 七、Vue 组件的本质是什么?(终极大白话解释)
✅ 一句话总结(通俗到家):
Vue 组件本质就是一个**“带有数据 + 模板 +行为的 JS 配置对象”**,Vue 会“读懂它”,翻译成真实页面 DOM 元素,并且自动帮我们“重新渲染”。
🔍 那么问题来了:我们写的 .vue
文件、<template>
标签,浏览器能直接看懂吗?
❌ 答案是:不能!
这些东西都是开发时写给 Vue 看的,不是写给浏览器直接看的。
浏览器认识的是 HTML、CSS、JavaScript,不认识什么 .vue
、<template>
、{{}}
双大括号这些“人类友好语法”。
🧠 那为什么我们能看到效果?Vue 做了什么?
因为 Vue 在你运行前,会 把你写的
.vue
文件编译成标准的 JavaScript 代码!
我们写的 .vue
文件👇:
<template><h1>{{ title }}</h1>
</template><script>
export default {data() {return {title: 'Hello Vue!'}}
}
</script>
Vue 会做这几件事(关键流程):
🔄 本质转换流程(一步步拆解)
步骤 | Vue 做的事情 | 举个比喻 |
---|---|---|
① | 读取 <template> 模板 | 看你准备怎么“画页面” |
② | 把模板编译成 render() 函数 | 生成画图步骤(JS代码) |
③ | 执行 render() → 得到虚拟 DOM(VNode) | 画一张草图(轻量版页面结构) |
④ | Vue 根据虚拟 DOM 真正生成 HTML 元素 | 真正把东西贴到网页上 |
⑤ | 数据变化时 → 自动重新画草图 → 更新页面 | 自动同步数据和页面 |
💡 所谓虚拟 DOM(VNode)是啥?
是一棵用 JavaScript 表示出来的“页面结构草图”。
举例:你写了这个 HTML:
<h1>Hello Vue!</h1>
Vue 内部生成类似这样的虚拟 DOM:
{tag: 'h1',children: ['Hello Vue!']
}
它不是真的标签,只是描述“我想画一个 h1,里面是 Hello Vue”。
然后 Vue 再把这个“草图”变成真的 HTML 插入页面。
🧑🎨 类比记忆(画画模型)
你 = 写 Vue 的人
.vue 文件 = 设计图(模板 + 数据 + 动作)
Vue = 智能画图机器人
虚拟 DOM = 草稿草图
真实 DOM = 最终画出来的图
流程如下:
你写 .vue 文件↓
Vue 编译成 render 函数↓
执行 render 得到虚拟 DOM(草稿图)↓
Vue 把虚拟 DOM 变成真实页面↓
数据变了 → Vue 自动重新画
📁 那么 .vue 文件到底能不能在浏览器里直接跑?
答案分两种情况:
场景 | 能否直接用 .vue 文件 |
---|---|
✅ 用 Vue CLI / Vite 等构建工具 | ✔ 能,它们帮你“提前编译好” |
❌ 直接用 CDN 引入 Vue.js(传统引入) | ❌ 不能,浏览器不认识 .vue 文件,需要手动注册组件 |
✅ 所以传统方式(不用 .vue 文件)要怎么写组件?
你要写成这样 ↓
Vue.component('my-card', {template: '<h1>{{ title }}</h1>',data() {return { title: 'Hello Vue!' }}
})
你不能写 .vue
文件,不能写 <template>
块,而是用字符串写模板。
✅ 总结大白话口诀
.vue 文件是开发者写的草图说明书
Vue 帮你翻译成 JS 渲染函数
虚拟 DOM 是草稿纸,不是最终成品
Vue 用它画出真实页面,自动刷新
是否需要我再画一张 “Vue 编译渲染流程图” 让学生可视化理解?或者补充一份“虚拟 DOM vs 真实 DOM 比较表”?只要说一声即可!
📝 八、总结记忆口诀
Vue 组件 = 结构(template)+ 行为(script)+ 样式(style)
✔ 写一个组件就像造一个乐高积木块
✔ 可以反复使用、传参定制、组合嵌套
📬 九、父子通信详解(props 与 $emit)
组件之间就像“家人聊天”:
- 🧒 父传子:爸爸给儿子一个任务(props 传值)
- 👨 子传父:儿子喊爸爸来处理事情($emit 触发事件)
✅ 父传子(Props)—— 接收数据的两种写法
✅ 基础写法:数组接收(只指定名字)
props: ['avatar', 'name']
📌 说明:
- 简洁写法,快速上手
- 适合新手练习和简单组件
- ❌ 没有类型校验,开发中容易出错
✅ 更推荐:对象写法(类型 + 是否必填 + 默认值)
props: {avatar: {type: String, // 限定类型为字符串required: true // 必传},name: {type: String, // 字符串类型default: '游客' // 没传就用默认值},age: {type: Number,validator: val => val > 0 && val < 120 // 自定义校验函数}
}
📌 每项支持配置:
属性 | 含义 |
---|---|
type | 限定传入值的类型(如:String) |
required | 是否必须传这个值(true/false) |
default | 没传时的默认值 |
validator | 自定义验证规则(函数返回 true 才通过) |
💡 示例对比
假设你使用组件时这样写:
<UserCard :avatar="user.img" :name="user.nick" :age="user.age" />
组件中这样定义 props:
props: {avatar: { type: String, required: true },name: { type: String, default: '匿名' },age: {type: Number,validator: val => val > 0 && val < 150}
}
👉 Vue 会自动帮你:
- 检查类型对不对(比如不能传数组给 name)
- 判断有没有传(比如 avatar 是不是漏了)
- 没传的补上默认值(比如 name = ‘匿名’)
⚠ 如果你在浏览器开启了 Vue 的开发者工具,控制台会提示错误或警告(开发时很有用)。
✅ 子传父($emit)
📌 场景:子组件想告诉父组件“我被点了”“我改名字了”“我完成了任务”
使用流程三步走:
1️⃣ 子组件里用 $emit
触发事件:
this.$emit('事件名', 参数)
this.$emit('follow-change', this.isFollowed)
2️⃣ 父组件监听事件:
<UserCard @follow-change="handleFollow" />
3️⃣ 父组件定义对应方法:
methods: {handleFollow(isFollowed) {console.log('关注状态变了:', isFollowed)}
}
🧠 理解类比:
动作 | 类比 |
---|---|
父传子(props) | 爸爸给你准备好资料 |
子传父($emit) | 你喊爸爸来处理事情 |
props 是单向的 | 只能“由上往下”流 |
不建议子组件修改 props | 否则容易出 bug |
✅ 子组件想修改 props 怎么办?
❌ 不能直接改(Vue 会警告),因为 props 是“外面传来的,不该动”
✅ 正确做法:拷贝一份再改
props: ['name'],
data() {return {editableName: this.name // 拷贝 props}
}
✍️ 小结记忆口诀
props 父传子,要用 :绑定
对象写法更规范,可设类型和校验
$emit 子传父,父用 @监听
props 是只读,修改要拷贝
十、插槽 slot(插内容的“万能口袋”)
插槽(slot)就是“组件留一个洞”,让别人来填。
✅ 默认插槽(基础用法)
Card.vue(子组件):
<template><div class="card"><slot></slot> <!-- 留个洞 --></div>
</template>
App.vue(父组件):
<Card><h2>我是插入的标题</h2><p>我是插入的内容</p>
</Card>
👉 页面会渲染:
<div class="card"><h2>我是插入的标题</h2><p>我是插入的内容</p>
</div>
✅ 具名插槽(多个“洞”)
Dialog.vue:
<template><div class="dialog"><header><slot name="title"></slot></header><main><slot></slot></main><footer><slot name="footer"></slot></footer></div>
</template>
使用:
<Dialog><template v-slot:title><h3>提示</h3></template><p>是否确认删除?</p><template v-slot:footer><button>取消</button><button>确认</button></template>
</Dialog>
📝 补充一句口诀记忆:
- 父传子 👉 props=“属性值”
- 子传父 👉 $emit(‘事件’)
- 插槽 slot 👉 留空洞给父塞
接下来介绍一下:对于 还没学 Vue 脚手架(Vue CLI / Vite)的实习生,传统引入式 Vue 页面中如何使用组件,也就是:
✅ 不用
npm install
、不用终端命令,只靠 HTML 引入 Vue 的方式来使用组件
🏗️ 十一、传统引入式页面中使用组件(不用脚手架)
📌 场景说明:
- 只用一个 HTML 文件
- 用
<script src="https://unpkg.com/vue@2">
引入 Vue - 在页面中直接写组件定义和注册
✅ 完整示例(UserCard 组件)
<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8"><title>传统引入式 Vue 组件使用</title><style>.user-card {border: 1px solid #ddd;padding: 10px;margin: 10px;text-align: center;}</style>
</head>
<body><div id="app"><user-card avatar="avatar1.png" name="Mike"></user-card><user-card avatar="avatar2.png" name="李四"></user-card></div><!-- 引入 Vue(使用 CDN) --><script src="https://unpkg.com/vue@2.7.14/dist/vue.js"></script><script>// 1️⃣ 定义组件Vue.component('user-card', {props: ['avatar', 'name'],data() {return {isFollowed: false}},methods: {toggleFollow() {this.isFollowed = !this.isFollowed}},template: `<div class="user-card"><img :src="avatar" alt="头像" width="80"><br><strong>{{ name }}</strong><br><button @click="toggleFollow">{{ isFollowed ? '已关注' : '关注' }}</button></div>`});// 2️⃣ 创建 Vue 实例new Vue({el: '#app'});</script>
</body>
</html>
✅ 步骤解释(通俗易懂):
步骤 | 做什么 | 说明 |
---|---|---|
① | Vue.component('组件名', {...}) | 注册一个全局组件 |
② | props: ['avatar', 'name'] | 接收父传入的属性 |
③ | template: \ …`` | 用字符串写模板,注意是反引号 ```包住 |
④ | new Vue({ el: '#app' }) | 创建 Vue 根实例 |
🧠 小提示
- 传统引入式项目只适合练习或小项目,不能模块化,也没有热更新。
- 将来学习 Vue CLI/Vite 后,你将能:
- 每个组件写成
.vue
文件(更清晰) - 用 import/export 模块化引入组件
- 自动编译、构建项目结构更清晰
- 每个组件写成
📦 总结:传统引入式组件用法口诀
Vue.component 注册组件
props 传值进组件
template 用字符串写结构
new Vue 启动应用
非常清楚了,你要的是组件使用细节层面、尤其是父子传值相关的 Vue 2 vs Vue 3 差异,要全面、准确、具体,不要泛泛而谈。以下是从实战角度出发的完整对比,仅涵盖组件使用+父子传值相关内容,适合实习生作为对照学习资料。
十二、 Vue 2 vs Vue 3 组件使用差异:含父子传值详解
一、组件定义与数据声明方式
项目 | Vue 2 | Vue 3 |
---|---|---|
组件定义方式 | Options API | Composition API |
响应式数据 | data() { return { msg: 'hello' } } | const msg = ref('hello') (需要 ref 或 reactive ) |
方法定义 | methods: { greet() { alert(this.msg) } } | const greet = () => alert(msg.value) |
this 的使用 | 必须用 this 访问数据和方法 | setup() 中完全不使用 this ,用变量作用域 |
二、父传子 props(传值)
✅ Vue 2 写法:
// 父组件模板
<Child :title="parentTitle" />// 子组件定义
export default {props: ['title'],mounted() {console.log(this.title)}
}
✅ Vue 3 写法:
// 父组件模板
<Child :title="parentTitle" />// 子组件定义(Composition API)
export default {props: ['title'],setup(props) {console.log(props.title)return { props }}
}
比较项 | Vue 2 | Vue 3 |
---|---|---|
props 接收 | props: [...] 或 props: {} ,内部用 this.xxx | props: [...] ,内部通过 setup(props) 获取 |
响应性 | props 是响应式的 | props 也是响应式的(但只读) |
注意事项 | props 是组件属性,不能修改 | props 是只读对象,修改会报错 |
三、子传父 emit(事件传值)
✅ Vue 2 写法:
// 子组件
this.$emit('update', '子组件传来的值')// 父组件模板
<Child @update="handleUpdate" />
✅ Vue 3 写法:
// 子组件 setup 内部
setup(props, { emit }) {emit('update', '子组件传来的值')return {}
}// 父组件模板
<Child @update="handleUpdate" />
比较项 | Vue 2 | Vue 3 |
---|---|---|
触发事件 | this.$emit() | emit() 来自 setup(_, { emit }) |
模板绑定事件 | @事件名="方法" | 相同 |
多参数 | $emit('doSomething', a, b) | emit('doSomething', a, b) |
四、双向绑定(v-model)组件绑定
✅ Vue 2 自定义 v-model:
// 子组件
props: ['value'],
methods: {update(val) {this.$emit('input', val)}
}
// 父组件
<Child v-model="formData" />
✅ Vue 3 自定义 v-model:
// 子组件
props: ['modelValue'],
emits: ['update:modelValue'],
setup(props, { emit }) {const update = (val) => emit('update:modelValue', val)return { update }
}
// 父组件
<Child v-model="formData" />
项目 | Vue 2 | Vue 3 |
---|---|---|
默认 prop 名 | value | modelValue |
默认事件名 | input | update:modelValue |
多个 v-model 支持 | 不支持多个 | 支持多个 v-model(可指定 prop 名) |
五、插槽(slot)传值差异
✅ Vue 2 插槽写法:
<slot></slot>
<slot name="footer"></slot>
✅ Vue 3 插槽写法:
相同,语法无变化。但 Composition API 中通常结合 setup()
结构使用,语义更清晰。
六、总结速查表(实习生重点记)
功能点 | Vue 2 | Vue 3 |
---|---|---|
组件数据 | data() 返回对象 | setup() + ref() 或 reactive() |
方法定义 | methods: {} | setup() 内部函数 |
props 接收 | props: [] + this.propName | setup(props) + props.propName |
emit 事件 | this.$emit() | setup(_, { emit }) + emit() |
v-model 实现 | value + input | modelValue + update:modelValue |
生命周期钩子 | created , mounted 等 | onMounted() , onUnmounted() 等组合函数 |
插槽写法 | <slot> <slot name> | 一致 |
七、 Vue 组件逻辑复用:mixin vs composable(实习生专用讲解)
❓ 什么是“组件逻辑复用”?
在开发中,多个组件之间会出现重复逻辑。比如:
- 获取用户信息
- 监听窗口大小
- 封装通用方法
我们不想重复写,就需要把这些逻辑“抽出来”给多个组件复用。
🟡 Vue 2 的写法:使用 mixin
🧩 示例:userMixin.js
// userMixin.js
export default {data() {return {username: '张三'}},methods: {sayHello() {console.log('你好,' + this.username)}}
}
在组件中使用:
import userMixin from './userMixin'export default {mixins: [userMixin],mounted() {this.sayHello()}
}
🧱 缺点:
- 不知道某个方法/变量是从哪里来的(代码不清晰)
- 多个 mixin 之间可能变量冲突
- 难维护,特别是大型项目
🟢 Vue 3 推荐写法:使用 组合函数 composable
本质:就是写成一个普通 JS 函数来封装逻辑,setup 中直接调用。
🧩 示例:useUser.js
// useUser.js
import { ref } from 'vue'export function useUser() {const username = ref('张三')const sayHello = () => {console.log('你好,' + username.value)}return { username, sayHello }
}
在组件中使用:
import { useUser } from './useUser'export default {setup() {const { username, sayHello } = useUser()sayHello()return { username }}
}
🧠 对比总结表
对比项 | Vue 2:mixin | Vue 3:组合函数(composable) |
---|---|---|
形式 | 混入对象 | 普通 JS 函数 |
使用位置 | mixins: [xxx] | setup() 中调用函数 |
数据访问 | this.xxx | 直接变量访问,不用 this |
命名冲突风险 | 有(多 mixin 冲突) | 没有,作用域清晰 |
可读性 | 差(不知道谁定义了什么) | 高(函数就是来源) |
推荐程度 | ❌ 不推荐(维护难) | ✅ 推荐(组合灵活) |
🎯 实习生记住:
Vue 2 用 mixin 抽公共逻辑,但容易冲突、难读;Vue 3 用组合函数
useXxx()
来封装逻辑,*清晰、独立、强类型,推荐使用!
逐项系统梳理 Vue 2 和 Vue 3 在“组件使用相关”的所有差异按实际开发中的常用点做全面比对
✅ Vue 2 vs Vue 3 ——组件相关完整对比
分类 | 差异点 | Vue 2 | Vue 3 |
---|---|---|---|
🧱 组件结构 | 写法风格 | Options API(配置式) | 推荐 Composition API(组合式) |
数据定义 | data() 返回对象 | setup() 中用 ref() 或 reactive() | |
方法定义 | methods: {} ,用 this.xxx() 调用 | setup() 中定义函数,直接使用 | |
访问变量 | 使用 this.xxx | 不使用 this ,直接使用变量 | |
计算属性 | computed: {} | const x = computed(() => ...) | |
生命周期钩子 | created , mounted , destroyed 等 | onMounted , onUnmounted , onUpdated 等 | |
返回给模板 | 隐式暴露所有 data/methods | setup() 需 return 暴露变量/函数 | |
✅ Props(父传子) | 定义方式 | props: ['title'] 或对象格式 | 相同写法 |
使用方式 | this.title | props.title (在 setup(props) 中) | |
响应性 | 响应式(但可写) | 响应式但只读(修改会报错) | |
✅ Emit(子传父) | 事件触发 | this.$emit('event', data) | emit('event', data) ,emit 从 setup(_, { emit }) 中解构 |
✅ v-model | 默认 prop 名 | value | modelValue |
默认事件名 | input | update:modelValue | |
多个 v-model | 不支持 | ✅ 支持多个:v-model:title 等 | |
✅ 插槽 slot | 基本写法 | <slot> , <slot name="footer"> | 相同写法,无变化 |
作用域插槽 | slot-scope 属性或 v-slot | 同样使用 v-slot ,更统一规范 | |
✅ 组件注册 | 局部注册 | components: { MyComp } | 相同 |
自动导入 | ❌(需要手动引入) | ✅ 在 <script setup> 中,使用即自动引入(需构建支持) | |
✅ 模板语法 | 模板绑定 | 一致:{{ }} 、@click 、:prop="val" 等 | 无变化 |
✅ 类型支持 | TypeScript 体验 | 支持较弱(this 上难推断) | TypeScript 支持更好,类型推断清晰 |
✅ 逻辑复用 | 推荐方式 | mixins(可能冲突) | ✅ 组合函数(composables) |
✅ 组件继承 | extends 支持 | ✅ extends: {} 支持继承 | 保留但较少使用,推荐组合而非继承 |
✅ 模板根元素 | 是否强制单根 | 必须单根 <div> | ✅ 可多个根节点(Fragment 支持) |
✅ 异步组件 | 加载方式 | Vue.component('Async', () => import('./Comp.vue')) | 相同写法,也可 defineAsyncComponent() |
✅ Teleport | 跨层渲染 | ❌ 不支持 | ✅ 新增 Teleport 组件,支持渲染到 body 等外部容器 |
✅ Suspense | 组件异步加载占位 | ❌ 不支持 | ✅ 新增 <Suspense> 组件支持异步加载 fallback 内容 |
最终小结(给实习生的核心概念):
Vue 3 在组件上做了四件大事:1. 推荐用 setup;2. 彻底不用 this;3. 事件通信写法变简单;4. 支持多个 v-model、Teleport 等高级用法。
原有的 Vue 2 写法大多数仍可使用,但推荐升级方式更灵活、结构更清晰、组合性更强。