告别 DOM “苦力活”:从原生 JS 到 Vue 3 的思维觉醒

60 阅读3分钟

从手动操作 DOM 到数据驱动:Vue 3 开发思维的转变

在前端开发的演进史中,从直接操作 DOM 到使用现代框架(如 Vue.js)的转变,不仅仅是语法的改变,更是一种开发思维的根本性重构。本文将结合一个经典的“Todo List”案例,深入探讨 Vue 是如何通过“数据驱动”和“虚拟 DOM”来提升开发体验与性能的。

一、 传统开发模式:命令式的机械劳动

在 Vue 出现之前,我们通常使用原生 JavaScript 或 jQuery 来开发页面。让我们看一眼 以下的代码片段,这代表了典型的命令式编程


// 摘自 demo.html
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;
    } else {
        app.innerHTML = todo; // 直接修改 DOM
    }
})

这种模式存在几个明显的痛点:

  1. 机械繁琐:你需要手动找到目标 DOM 元素(getElementById),然后对其进行修改。
  2. 性能瓶颈:JavaScript 引擎(如 V8)运行速度极快,但浏览器的渲染引擎相对较慢。频繁地手动操作 DOM 会导致浏览器频繁重排和重绘,造成性能浪费。
  3. 心智负担:开发者需要同时关注“数据是什么”以及“怎么把数据渲染到页面上”,代码容易变得杂乱。

这种方式需要:“先找到 DOM 元素,命令式,机械的,性能差的。

二、 Vue 的变革:数据驱动与声明式编程

Vue 的出现改变了游戏规则。在 Vue 中,我们不再需要思考页面的元素怎么操作,而是要思考数据是怎么变化的

让我们看看以下代码是如何实现同样的业务逻辑的:

<script setup>
import { ref } from 'vue';

// 1. 定义响应式数据
const todos = ref([
  { id: 1, context: '打王者', done: false },
  // ...
]);

// 2. 仅修改数据,无需触碰 DOM
const addTodo = () => {
  todos.value.push({
    id: nextId++,
    context: text,
    done: false
  });
}
</script>

<template>
  <li v-for="todo in todos" :key="todo.id">
    {{ todo.context }}
  </li>
</template>

在 Vue 3 的组合式 API(Composition API)中:

  • 我们使用 ref 定义响应式数据。
  • addTodo 函数执行时,我们只关心 todos 数组的数据变更(push)。
  • Vue 底层会自动感知数据的变化,并更新视图。

这种声明式的写法让开发者从繁琐的 DOM 操作中解放出来,专注于业务逻辑本身。

三、 揭秘幕后英雄:虚拟 DOM (Virtual DOM)

为什么 Vue 操作数据就能自动更新页面,而且性能还比手动操作好?这归功于 虚拟 DOM

总结虚拟 DOM 的核心机制:

  1. 本质:虚拟 DOM 本质上是一个轻量级的 JavaScript 对象,用来描述真实的 DOM 结构。操作 JS 对象比操作真实 DOM 快得多。
  2. Diff 算法:当数据发生变化时,Vue 会生成一个新的虚拟 DOM 树,并与旧的树进行对比(Diff),计算出最小的变更点。
  3. 批量更新:Vue 会将多次数据变更合并,在一次更新周期内批量应用到真实 DOM 上,避免了浏览器的频繁渲染。

四、 总结

通过对比,我们可以清晰地看到:

  • 传统做法是关注“过程”:第一步找元素,第二步改样式,第三步改内容。
  • Vue 做法是关注“状态”:我改变了数据,界面就应该是这个样子的。

Vue 通过 响应式系统虚拟 DOM,不仅替我们完成了脏活累活(DOM 操作),还保证了性能的下限。对于开发者而言,这意味着更低的心智负担、更高的代码质量以及更易维护的项目结构。