在前端开发的演进过程中,我们经历了从原生 JavaScript 手动操作 DOM 到现代框架如 Vue 的声明式、响应式编程范式的巨大转变。本文将通过一个简单的“任务清单(Todos)”应用,对比传统 JS 开发思路与 Vue 3 Composition API 的开发方式,深入剖析这种思维模式的升级,并解释其背后的核心理念与性能优势。
一、传统开发:命令式 DOM 操作的痛点
在没有框架的时代,我们通常这样写代码:
<h2 id="app"></h2>
<input type="text" id="todo-input">
<script>
const app = document.getElementById('app')
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>
这段代码看似简单,但隐藏着几个关键问题:
- 命令式操作:我们必须手动查找 DOM 元素(
getElementById),再通过innerHTML修改内容。这是一种“告诉浏览器每一步该做什么”的机械式编程。 - 性能隐患:每次赋值
app.innerHTML = todo都会触发重排(reflow)和重绘(repaint) 。重排涉及布局计算,代价高昂;即使只是文本更新,也可能导致整个子树重建。 - 状态与 UI 耦合:UI 的更新逻辑直接写在事件回调中,难以复用、测试或维护。当功能复杂时(如增删改查、筛选、全选等),代码迅速变得混乱。
“从 JS(V8引擎 快) -> HTML(渲染引擎 慢) 查找”,这种跨引擎通信本身就是性能瓶颈。
二、Vue 的核心思想:描述 UI 与状态的关系
Vue 的出现,彻底改变了这一局面。它让我们从“如何操作 DOM”转向“UI 应该是什么样子”,即声明式编程。
在 Vue 3 中,我们不再关心 DOM 操作细节,而是聚焦于数据本身的变化。框架会自动追踪依赖,并高效地更新视图。
以下是一个完整的 Vue 3 版 Todos 组件(使用 <script setup> 语法):
<template>
<div>
<!-- 数据绑定 -->
<h2>{{ title }}</h2>
<!-- v-model 双向数据绑定 -->
<!-- @ 是 v-on: 的缩写 用于绑定事件 不用addEventListener -->
<!-- @event-name.enter 监听键盘输入 当按下回车的时候触发addTodo函数执行 -->
<input type="text" v-model="title" @keydown.enter="addTodo">
<!-- v-if 条件渲染指令 只有当有数据时 再去循环遍历 -->
<ul v-if="todos.length">
<!-- :key 循环的标配 需要给它key 作为唯一属性 -->
<li v-for="todo in todos" :key="todo.id">
<input type="checkbox" v-model="todo.done">
<!-- : 是v-bind: 的缩写 表示 :里面是JS表达式-->
<span :class="{done: todo.done}">{{ todo.title }}</span>
<!-- :class 动态绑定class 通过todo.done 控制类名 是动态的 当todo.done为true 则添加done类 当todo.done为false 则不添加该类 -->
</li>
</ul>
<!-- 没有数据 -->
<div v-else>
暂无计划
</div>
<div>
全选<input type="checkbox" v-model="allDone">
<!-- v-model='allDone' 实际调用set(val) -->
<!-- {{ 数据绑定 也可以是表达式的结果绑定 }} 计算之后的数据绑定 -->
<!-- 未完成任务的长度(个数) -->
<!-- {{ todos.filter(todo => !todo.done).length }}
/
{{ todos.length }} -->
<!-- 总共的长度 -->
{{ active }}
/
{{ todos.length }}
<!-- 哪个更优秀? computed -->
</div>
</div>
</template>
<script setup>//setup vue3 composition 组合式API 如果不是setup vue2 options API
// 业务是页面上要动态展示标题 且支持编辑标题
// vue 让我们能够focus于标题数据业务 当修改数据时 余下的DOM更新 Vue替我们做了
import { ref, computed } from 'vue'
//响应式数据
const title = ref('')
const todos = ref([
{
id: 1,
title: '打王者',
done: false
},
{
id: 2,
title: '吃饭',
done: true
},
])
const addTodo = () => {
// focus 数据业务
if(!title.value) return
todos.value.push({
id: Math.random(),
title: title.value,
done: false
})
//添加过后 清空表单
title.value = ''
}
//依赖于todos响应式数据的 计算属性
//形式上是函数(计算过程) 计算结果(计算属性)返回
//也是响应式的 依赖于todos
const active = computed(() => {
return todos.value.filter(todo => !todo.done).length
})
//全选
// computed 高级技巧
// get set 属性的概念
const allDone = computed({
get(){
//判断是否全选 (所有的done === true)
return todos.value.every(todo => todo.done)
},
set(val){
//批量设置所有todo.done 当用户点击'全选'复选框时 val设置为true 或 false 勾选 或 取消勾选
todos.value.forEach(todo => todo.done = val)
}
})
</script>
<style>
/* 在样式部分设置一横杠 */
.done{
text-decoration: line-through;
}
</style>
三、Vue 开发范式的五大优势
1. 响应式数据驱动
通过 ref() 创建响应式变量,任何对其 .value 的修改都会自动触发视图更新。开发者只需关注“数据怎么变”,无需手动操作 DOM。
“Vue 让我们能够 focus 于标题数据业务,当修改数据时,余下的 DOM 更新 Vue 替我们做了。”
2. 指令系统简化逻辑
v-model:实现双向绑定,省去addEventListener和手动同步。v-for+:key:高效列表渲染,key帮助 Vue 识别节点身份,最小化 DOM 操作。v-if/v-else:条件渲染,逻辑清晰。@keydown.enter:事件修饰符,简洁监听特定键盘事件。
这些指令让模板语义更明确,代码可读性大幅提升。
3. 计算属性(computed)的性能优化
对比两种写法:
<!-- ❌ 直接在模板中写表达式 -->
{{ todos.filter(todo => !todo.done).length }}
<!-- ✅ 使用 computed -->
{{ active }}
前者每次组件重新渲染(哪怕与 todos 无关的数据变化)都会重新执行过滤,因为它就是一个计算、一个表达式,它不会拒绝更新;而 computed 具备缓存机制,只有todos变化时才会重新计算:
“内部维护一个
_dirty标志,当依赖的响应式数据变化时标记为 dirty,下次读取时如果是 dirty 则重新计算并缓存结果,否则直接返回缓存值。”
这避免了不必要的重复计算,显著提升性能。
4. 高级 computed:getter/setter 实现复杂逻辑
全选功能通过 computed 的 get/set 实现:
const allDone = computed({
get() {
return todos.value.every(todo => todo.done)
},
set(val) {
todos.value.forEach(todo => todo.done = val)
}
})
当用户点击“全选”复选框时,v-model="allDone" 会调用 set 方法,批量更新所有任务状态。这种模式将 UI 行为与数据逻辑完美解耦。
5. 虚拟 DOM 与高效更新
虽然开发者不直接接触 DOM,但 Vue 底层通过虚拟 DOM(VNode) 实现高性能更新:
“Vue 将模板编译为 render 函数,生成 VNode(虚拟节点)。更新时,对比新旧 VNode 树,最小化真实 DOM 操作。”
这意味着即使你写了看似“暴力”的数据变更(如替换整个数组),Vue 也能智能 diff,只更新真正变化的部分。
四、思维转变:从“操作 DOM”到“管理状态”
传统开发的核心是 “找到元素 → 修改它” ,而 Vue 的核心是 “定义状态 → 描述 UI 如何随状态变化” 。
这种转变带来三大好处:
- 降低心智负担:新手无需理解 DOM 树、事件冒泡、重排重绘等底层概念,也能写出高质量代码。
- 提升可维护性:数据流清晰,逻辑集中,便于调试和扩展。
- 天然支持组件化:每个组件管理自己的状态和 UI,组合成复杂应用。
“Vue 开发方式 简单 高效 好上手”。
结语
从原生 JS 到 Vue 3,不仅是工具的升级,更是编程范式的跃迁。我们不再被 DOM 操作束缚,而是站在更高维度思考应用的状态与交互。Vue 的响应式系统、指令语法、计算属性和虚拟 DOM 共同构建了一个高效、直观、可维护的开发体验。
对于初学者,Vue 让你快速上手;对于资深开发者,它提供了足够的灵活性与性能保障。在这个“数据驱动 UI”的时代,掌握 Vue 的声明式思维,就是掌握了现代前端开发的核心能力。