💡 真实故事:曾经的我,用原生 JavaScript 写一个 Todo 应用,写了 100+ 行代码,还各种 bug。直到遇见了 Vue 3,同样的功能,50 行搞定,而且代码清晰得像诗一样!
🎬 开场:一个程序员的"觉醒"
场景一:使用原生 JavaScript
// 早上 9:00,开始写 Todo 应用
const input = document.getElementById('input');
const list = document.getElementById('list');
const count = document.getElementById('count');
// 10:00,还在写事件监听
input.addEventListener('keydown', function(e) {
if (e.key === 'Enter') {
// 11:00,还在手动更新 DOM
const li = document.createElement('li');
li.textContent = input.value;
list.appendChild(li);
// 12:00,发现计数没更新,继续改...
// 13:00,发现样式没更新,继续改...
// 14:00,发现全选功能有问题,继续改...
// 我:我太难了!😭
}
});
场景二:使用 Vue 3
<!-- 早上 9:00,开始写 Todo 应用 -->
<input v-model="newTodo" @keydown.enter="addTodo">
<li v-for="todo in todos" :key="todo.id">
{{ todo.title }}
</li>
<!-- 9:05,功能完成!代码清晰,功能完美!✨ -->
这就是 Vue 3 的力量! 💪
🎯 前言:从"搬砖"到"搭积木"的华丽转身
还记得第一次用原生 JavaScript 操作 DOM 的痛苦吗?😭
// 我:我要更新一个列表
document.getElementById('list').innerHTML = ''; // 先清空
todos.forEach(todo => {
const li = document.createElement('li'); // 创建元素
li.textContent = todo.title; // 设置内容
document.getElementById('list').appendChild(li); // 添加到DOM
// 还要手动绑定事件...
// 还要手动更新计数...
// 还要手动更新样式...
// 我:我太难了!😫
});
Vue 3 说:兄弟,别这么累!
<!-- 我:我要更新一个列表 -->
<li v-for="todo in todos" :key="todo.id">
{{ todo.title }}
</li>
<!-- Vue:搞定!自动更新、自动绑定、自动优化!✨ -->
这就是 Vue 3 的魅力!🎉 今天,我们就通过一个任务清单应用,看看 Vue 3 是如何把我们从"DOM 搬砖工"变成"优雅架构师"的!
📋 项目概览:我们要做什么?
今天我们要打造一个超酷的任务清单应用!功能虽然简单,但能让你深刻理解 Vue 3 的强大!
功能清单:
- ✅ 添加新任务(按回车秒添加)
- ✅ 标记任务完成/未完成(一键切换)
- ✅ 全选/取消全选(批量操作神器)
- ✅ 显示未完成任务数量(实时统计)
目标: 用最少的代码,实现最优雅的功能!💪
原生 JavaScript vs Vue 3:一场"降维打击"的较量
🔨 原生 JavaScript:手动档的"老司机"
想象一下,你要开车,但必须手动控制每一个细节:换挡、踩离合、打方向盘...这就是原生 JavaScript!
<!-- 原生 JS:我要手动控制一切! -->
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>原生 JS Todo</title>
</head>
<body>
<h2 id="app"></h2>
<input type="text" id="todo-input">
<script>
// vue 之前--->找到 DOM 元素
// JS v8(快)引擎到html(慢)渲染引擎
// 先找到DOM元素 命令式的,机械的,性能差的 vue 底层也做,但是它会代替我们做
// 响应式 数据驱动 focus 数据业务
// vue 让新手写的代码质量更好,容易入门 v-for {{}} ref
const app = document.getElementById('app');
// 获取 DOM 元素
const todoInput = document.getElementById('todo-input');
// 监听用户输入事件
todoInput.addEventListener('change', function(event) {
const todo = event.target.value.trim();
if(!todo) {
console.log('请输入任务');
return;
}
// 根据用户输入动态更新页面内容
app.innerHTML = todo;
})
</script>
</body>
</html>
🚀 Vue 3:自动档的"智能驾驶"
而 Vue 3 就像特斯拉的自动驾驶,你只需要说"我要去这里",它自动帮你搞定一切!
<!-- Vue 3:我只需要声明"我要什么",Vue 自动帮我实现! -->
<template>
<div>
<h2>{{ title }}</h2>
<!-- 双向绑定?一行搞定! -->
<input type="text" v-model="title" @keydown.enter="addTodo">
<!-- 全选功能?自动同步! -->
<div>
全选 <input type="checkbox" v-model="allDone">
</div>
<!-- 列表渲染?自动更新! -->
<ul v-if="todos.length">
<li v-for="todo in todos" :key="todo.id">
<input type="checkbox" v-model="todo.done">
<!-- 动态样式?自动应用! -->
<span :class="{done: todo.done}">{{ todo.title }}</span>
</li>
</ul>
<div v-else>暂无计划</div>
<!-- 计数?自动计算! -->
<div>{{ active }}/{{ todos.length }}</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const todos = ref([])
const title = ref("todos 任务清单")
const active = computed(() => {
return todos.value.filter(todo => !todo.done).length
})
const addTodo = () => {
if (title.value.trim()) {
todos.value.push({
id: Math.random(),
title: title.value.trim(),
done: false
})
title.value = ''
}
}
const allDone = computed({
get() {
return todos.value.length > 0 &&
todos.value.every(todo => todo.done)
},
set(value) {
todos.value.forEach(todo => {
todo.done = value
})
}
})
</script>
核心差异对比表
| 特性 | 原生 JavaScript | Vue 3 |
|---|---|---|
| DOM 操作方式 | 命令式:手动查找、操作 DOM | 声明式:数据驱动,自动更新 |
| 代码复杂度 | 需要手动管理 DOM 更新 | 自动同步数据与视图 |
| 性能优化 | 需要手动优化 DOM 操作 | 虚拟 DOM + diff 算法 |
| 数据绑定 | 手动监听事件,手动更新 | v-model 双向绑定 |
| 列表渲染 | 手动循环创建 DOM 元素 | v-for 自动渲染 |
| 条件渲染 | if/else + DOM 操作 | v-if/v-else 声明式 |
| 响应式系统 | 无,需手动实现 | 自动响应式更新 |
| 代码可读性 | 低,关注 DOM 操作细节 | 高,关注业务逻辑 |
🎯 Vue 3 的五大"超能力"
1. 🎨 数据驱动 vs 命令式操作:从"指挥家"到"作曲家"
原生 JavaScript(命令式):像指挥家,每个动作都要指挥
// 我:找到那个元素!
const app = document.getElementById('app');
const todoInput = document.getElementById('todo-input');
// 我:监听那个事件!
todoInput.addEventListener('change', function(event) {
// 我:更新那个内容!
app.innerHTML = event.target.value;
// 我:好累...
})
Vue 3(声明式):像作曲家,只需要写乐谱,乐队自动演奏
<!-- 我:我要标题显示 title,输入框绑定 title -->
<h2>{{ title }}</h2>
<input v-model="title">
<!-- Vue:收到!自动同步!✨ -->
优势:
- ✅ 无需手动操作 DOM(告别
getElementById地狱) - ✅ 数据变化自动更新视图(像魔法一样!)
- ✅ 代码更简洁,关注业务逻辑(写代码像写诗)
2. 🔄 响应式系统:像"智能管家"一样贴心
原生 JavaScript:像手动开关,每个灯都要手动开
// 我:添加一个任务
let todos = [];
function addTodo(todo) {
todos.push(todo);
// 我:更新列表!
updateTodoList();
// 我:更新计数!
updateCount();
// 我:更新全选状态!
updateAllDone();
// 我:还有没有漏掉的?😰
}
Vue 3:像智能家居,说一句话,所有设备自动响应
const todos = ref([])
function addTodo(todo) {
todos.value.push(todo)
// Vue:检测到数据变化!
// Vue:自动更新列表 ✅
// Vue:自动更新计数 ✅
// Vue:自动更新全选状态 ✅
// Vue:所有相关视图已同步!✨
}
优势:
- ✅ 自动追踪依赖(Vue 知道谁依赖谁)
- ✅ 数据变化时自动更新相关视图(像魔法!)
- ✅ 无需手动管理更新逻辑(告别
updateXXX函数地狱)
3. 🔗 双向数据绑定:像"量子纠缠"一样神奇
原生 JavaScript:像手动同步两个时钟
// 我:数据变了,更新视图!
const input = document.getElementById('input');
const display = document.getElementById('display');
// 我:数据 → 视图
display.textContent = data.value;
// 我:视图变了,更新数据!
input.addEventListener('input', function(e) {
data.value = e.target.value;
display.textContent = data.value; // 还要手动更新显示
// 我:好麻烦...
});
Vue 3:像量子纠缠,一个变化,另一个自动同步
<!-- 我:我要双向绑定 -->
<input v-model="title">
<h2>{{ title }}</h2>
<!-- Vue:收到!自动同步!无论谁变,另一个自动跟着变!✨ -->
优势:
- ✅ 一行代码实现双向绑定(告别
addEventListener) - ✅ 自动同步数据与视图(像魔法一样!)
- ✅ 减少样板代码(代码量减少 90%!)
4. 📝 列表渲染:从"手工制作"到"批量生产"
原生 JavaScript:像手工制作,每个都要亲手做
// 我:创建一个列表项
const ul = document.querySelector('ul');
todos.forEach(todo => {
const li = document.createElement('li'); // 创建元素
li.textContent = todo.title; // 设置内容
ul.appendChild(li); // 添加到DOM
// 我:好累...😫
});
// 我:数据变了,重新做一遍!
function updateList() {
ul.innerHTML = ''; // 全部清空
todos.forEach(todo => { // 重新创建
const li = document.createElement('li');
li.textContent = todo.title;
ul.appendChild(li);
});
// 我:又要重新做一遍...😭
}
Vue 3:像3D打印,说一声,自动批量生产
<!-- 我:我要渲染这个列表 -->
<ul>
<li v-for="todo in todos" :key="todo.id">
{{ todo.title }}
</li>
</ul>
<!-- Vue:收到!自动渲染!数据变化?自动更新!✨ -->
优势:
- ✅ 声明式语法,代码更清晰(像读诗一样)
- ✅ 自动处理列表更新(告别
innerHTML = '') - ✅ 虚拟 DOM 优化性能(只更新变化的部分)
5. ⚡ 性能优化:从"拆了重建"到"精准手术"
原生 JavaScript:像拆房子重建,每次都全部重来
// 我:更新列表
function updateList() {
const ul = document.querySelector('ul');
ul.innerHTML = ''; // 拆掉所有房子
todos.forEach(todo => {
const li = document.createElement('li'); // 重新建房子
ul.appendChild(li);
});
// 我:只改了一个任务,却要重建整个列表...😤
}
Vue 3:像精准手术,只改需要改的地方
<!-- Vue:使用虚拟 DOM + diff 算法 -->
<!-- 我:只改了一个任务?只更新那一个! -->
<li v-for="todo in todos" :key="todo.id">
<!-- Vue:智能对比,精准更新!✨ -->
优势:
- ✅ 虚拟 DOM 减少真实 DOM 操作(性能提升 10 倍!)
- ✅ diff 算法只更新变化部分(像精准手术)
- ✅ 自动优化,无需手动处理(Vue 帮你搞定一切)
完整代码对比
原生 JavaScript 完整实现(复杂版)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>原生 JS Todo</title>
</head>
<body>
<h2 id="title">todos 任务清单</h2>
<input type="text" id="todo-input" placeholder="输入任务...">
<div>
全选 <input type="checkbox" id="all-done">
</div>
<ul id="todo-list"></ul>
<div id="count"></div>
<script>
// 数据
let todos = [];
let title = "todos 任务清单";
// DOM 元素
const titleEl = document.getElementById('title');
const inputEl = document.getElementById('todo-input');
const listEl = document.getElementById('todo-list');
const countEl = document.getElementById('count');
const allDoneEl = document.getElementById('all-done');
// 更新标题
function updateTitle() {
titleEl.textContent = title;
}
// 更新列表
function updateList() {
listEl.innerHTML = '';
todos.forEach(todo => {
const li = document.createElement('li');
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.checked = todo.done;
checkbox.addEventListener('change', () => {
todo.done = checkbox.checked;
updateCount();
updateAllDone();
});
const span = document.createElement('span');
span.textContent = todo.title;
if (todo.done) {
span.style.color = 'gray';
span.style.textDecoration = 'line-through';
}
li.appendChild(checkbox);
li.appendChild(span);
listEl.appendChild(li);
});
}
// 更新计数
function updateCount() {
const active = todos.filter(t => !t.done).length;
countEl.textContent = `${active}/${todos.length}`;
}
// 更新全选状态
function updateAllDone() {
allDoneEl.checked = todos.length > 0 && todos.every(t => t.done);
}
// 添加任务
function addTodo() {
const value = inputEl.value.trim();
if (!value) return;
todos.push({
id: Math.random(),
title: value,
done: false
});
inputEl.value = '';
updateList();
updateCount();
updateAllDone();
}
// 全选/取消全选
allDoneEl.addEventListener('change', (e) => {
todos.forEach(todo => {
todo.done = e.target.checked;
});
updateList();
updateCount();
});
// 监听输入
inputEl.addEventListener('keydown', (e) => {
if (e.key === 'Enter') {
addTodo();
}
});
// 初始化
updateTitle();
updateList();
updateCount();
updateAllDone();
</script>
</body>
</html>
Vue 3 完整实现
<template>
<div>
<h2>{{ title }}</h2>
<input
type="text"
v-model="newTodo"
@keydown.enter="addTodo"
placeholder="输入任务..."
>
<div>
全选 <input type="checkbox" v-model="allDone">
</div>
<ul v-if="todos.length">
<li v-for="todo in todos" :key="todo.id">
<input type="checkbox" v-model="todo.done">
<span :class="{done: todo.done}">{{ todo.title }}</span>
</li>
</ul>
<div v-else>暂无计划</div>
<div>{{ active }}/{{ todos.length }}</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const todos = ref([])
const title = ref("todos 任务清单")
const newTodo = ref('')
const active = computed(() => {
return todos.value.filter(todo => !todo.done).length
})
const addTodo = () => {
if (newTodo.value.trim()) {
todos.value.push({
id: Math.random(),
title: newTodo.value.trim(),
done: false
})
newTodo.value = ''
}
}
const allDone = computed({
get() {
return todos.value.length > 0 &&
todos.value.every(todo => todo.done)
},
set(value) {
todos.value.forEach(todo => {
todo.done = value
})
}
})
</script>
<style scoped>
.done {
color: gray;
text-decoration: line-through;
}
</style>
📊 代码量对比:数字不会说谎!
| 功能 | 原生 JavaScript | Vue 3 | 减少比例 | 我的感受 |
|---|---|---|---|---|
| 总行数 | ~100 行 😫 | ~50 行 😊 | 50% | 工作量减半! |
| DOM 操作代码 | ~60 行 😭 | 0 行 ✨ | 100% | 彻底解放! |
| 事件监听代码 | ~20 行 😤 | 2 行 🎉 | 90% | 轻松多了! |
| 更新逻辑代码 | ~20 行 😰 | 0 行(自动) 🚀 | 100% | Vue 自动搞定! |
结论: Vue 3 让你用一半的代码,实现更好的功能!这就是"降维打击"!💪
🎓 Vue 3 Composition API 核心概念:从"写作文"到"写诗"
💭 思考题:为什么 Vue 3 要引入 Composition API?答案在文章最后揭晓!
1. 🍬 <script setup> 语法糖:让代码像诗一样简洁
<script setup> 是 Vue 3 的"语法糖",甜到心里!🍭
特点:
- ✅ 自动暴露顶层变量和函数给模板(不用写 return)
- ✅ 无需手动 return(告别样板代码)
- ✅ 代码更简洁(像写诗一样优雅)
对比传统写法:
// Options API (Vue 2)
export default {
data() {
return {
todos: []
}
},
methods: {
addTodo() { ... }
}
}
// Composition API (Vue 3)
<script setup>
const todos = ref([])
const addTodo = () => { ... }
</script>
2. ref - 响应式数据的基础:给数据装上"雷达"
ref 就像给数据装上"雷达",Vue 能随时知道数据的变化!
const todos = ref([])
const title = ref("todos 任务清单")
// Vue:收到!我已经在监控这些数据了!👀
关键点(记住这三点,你就是 Vue 高手!):
- 原始值会被包装成对象(Vue 的魔法)
- 访问/修改需要使用
.value(在 script 中) - 模板中自动解包,无需
.value(Vue 的贴心)
// 在 script 中:需要 .value(因为被包装了)
todos.value.push(newTodo) // ✅ 正确
// 在 template 中:自动解包(Vue 帮你搞定)
{{ todos }} // ✅ 正确,不需要 .value
3. 🧮 computed - 计算属性:像"智能计算器"一样聪明
计算属性就像"智能计算器",会记住结果,只有依赖变化时才重新计算!
// 简单计算属性(只读):像只读的计算器
const active = computed(() => {
return todos.value.filter(todo => !todo.done).length
// Vue:我记住了!只有 todos 变化时才重新计算!🧠
})
带 getter/setter 的计算属性(可读写):像可写的计算器
const allDone = computed({
get() {
// 当读取 allDone 时执行(像读取计算器结果)
return todos.value.length > 0 &&
todos.value.every(todo => todo.done)
},
set(value) {
// 当设置 allDone 时执行(像设置计算器)
// 比如:v-model="allDone" 时会调用这里
todos.value.forEach(todo => {
todo.done = value
})
}
})
优势(这就是为什么 computed 这么强大):
- ✅ 缓存:依赖不变时不重新计算(性能优化神器)
- ✅ 响应式:依赖变化时自动更新(像魔法一样)
- ✅ 可读写:通过 getter/setter 实现双向绑定(一个顶俩)
4. 模板指令详解
v-model - 双向数据绑定
<input type="text" v-model="title">
等价于:
<input
:value="title"
@input="title = $event.target.value"
>
v-for - 列表渲染
<li v-for="todo in todos" :key="todo.id">
关键点:
:key提供唯一标识,优化性能- 支持解构:
v-for="({ id, title }, index) in todos"
v-if / v-else - 条件渲染
<ul v-if="todos.length">
<!-- 有任务时显示 -->
</ul>
<div v-else>
暂无计划
</div>
:class - 动态 class 绑定
<span :class="{done: todo.done}">{{ todo.title }}</span>
当 todo.done 为 true 时,应用 done 类。
5. 事件处理
<input @keydown.enter="addTodo">
@是v-on:的简写.enter是按键修饰符- 支持
.prevent、.stop等修饰符
Vue 3 的核心特性总结
1. 声明式编程
- ✅ 关注"做什么",而不是"怎么做"
- ✅ 代码更易读、易维护
2. 响应式系统
- ✅ 自动追踪依赖
- ✅ 数据变化自动更新视图
- ✅ 无需手动管理更新
3. 组件化开发
- ✅ 可复用的组件
- ✅ 更好的代码组织
- ✅ 便于团队协作
4. 性能优化
- ✅ 虚拟 DOM
- ✅ diff 算法
- ✅ 自动优化
5. 开发体验
- ✅ 友好的 API
- ✅ 丰富的工具链
- ✅ 完善的文档
为什么选择 Vue 3?
- 学习曲线平缓:语法直观,易于上手
- 开发效率高:减少样板代码,专注业务
- 性能优秀:虚拟 DOM 和响应式系统优化
- 生态完善:丰富的插件和工具
- 社区活跃:问题容易得到解答
最佳实践建议
- 使用
ref处理原始值,reactive处理对象 - 计算属性用于派生状态,避免在模板中写复杂逻辑
v-for必须提供:key- 使用
<script setup>简化代码 - 合理使用
computed的缓存特性
🎉 总结:从"搬砖工"到"架构师"的华丽转身
通过对比原生 JavaScript 和 Vue 3 的实现,我们可以清楚地看到:
💪 Vue 3 的四大"超能力"
- 开发效率提升 100%:代码量减少约 50%,告别 DOM 操作地狱
- 代码可读性提升 200%:声明式语法,像读诗一样优雅
- 维护成本降低 300%:数据驱动,自动更新,告别手动同步
- 性能提升 500%:虚拟 DOM + diff 算法,自动优化
🚀 我的真实感受
使用原生 JavaScript 时:
- 写 100 行代码,各种 bug
- 手动操作 DOM,累到怀疑人生
- 维护代码,改一处要改十处
使用 Vue 3 后:
- 写 50 行代码,功能完美
- 声明式编程,代码像诗一样
- 自动更新,维护轻松愉快
Vue 3 的 Composition API 不仅提供了更好的代码组织方式,更重要的是它让开发者从繁琐的 DOM 操作中解放出来,专注于业务逻辑的实现。
这就是 Vue 3 的魅力:让你从"搬砖工"变成"架构师"! 🏗️
💬 写在最后
如果你还在用原生 JavaScript 操作 DOM,还在写 getElementById、addEventListener、innerHTML...
兄弟,该升级了! 🚀
Vue 3 不是框架,是开发方式的革命!
- 告别 DOM 操作地狱
- 告别手动同步数据
- 告别重复的样板代码
- 拥抱声明式编程
- 拥抱响应式系统
- 拥抱更好的开发体验
让我们一起拥抱 Vue 3,享受开发的乐趣!