🚀 从 DOM 机械师到数据魔术师:Vue 入门第一课

56 阅读9分钟

嗨,未来的 Vue 大佬们!👋 相信不少小伙伴和我一样,在踏入前端世界时,都是从原生 JavaScript 开始的。我们熟练地使用 document.getElementByIdaddEventListener,然后手动修改 innerHTMLstyle 等等,就像一个勤劳的 DOM "机械师"一样,一步步、命令式地告诉浏览器:“先找到这个元素,然后给它改个颜色,再加个列表项……”

但说实话,这种传统做法在项目变大、逻辑变复杂后,会变得异常痛苦、机械且容易出错。性能优化?元素复用?那更是让人头疼!

好消息来了! 🎉 Vue.js 的出现,彻底改变了这种局面。它提供了一种响应式数据驱动的界面开发模式,让我们的关注点从如何操作页面元素彻底转移到数据是如何变化的上来。

💡 Vue 的核心思想:响应式与数据驱动

在上面的 Todo 任务清单示例中,我们清晰地看到了两种截然不同的做法:

1. 传统做法(DOM 命令式操作)

在 HTML 底部嵌入的 <script> 标签中,我们用原生 JS 实现了最基本的任务添加功能:

JavaScript

// 找到DOM元素 命令式,机械的,性能差的
// js(v8 快) -> html(渲染引擎 慢),vue底层也做。代替我们做
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;
    }
    // 关键点:直接操作 DOM,将值赋给 innerHTML
    app.innerHTML = todo; 
});
  • 传统做法的弊端:

    • 命令式: 我们必须告诉浏览器每一步怎么做(找到DOM -> 添加事件 -> 修改innerHTML)。
    • 机械性: 逻辑复杂时,需要大量的 DOM 查询和操作代码。
    • 性能差: 频繁、直接地操作 DOM 元素比操作纯粹的 JavaScript 对象要慢得多。虽然浏览器底层渲染引擎(慢)是不可避免的,但 Vue 替我们做这些操作,大大优化了操作的效率和时机

2. Vue 做法(数据驱动与响应式)

在 Vue 的 <script setup><template> 中,我们几乎看不到任何 DOM 操作的代码。我们只专注于数据的定义和数据变化的逻辑:

  • 我们定义了 titletodos 响应式数据
  • <template> 中,我们使用 Vue 的模板语法,将这些数据“绑定”到 HTML 结构上。
  • 当用户输入任务时,我们只执行 todos.value.push(...)title.value = ''修改数据
  • 神奇的地方: 剩下的 DOM 更新、界面渲染,Vue 会自动、高效地帮我们完成!

Vue 做法的核心理念: 不再需要思考页面元素怎么操作,而是要思考数据是怎么变化的。 我们的工作变成了**“聚焦数据业务” ,而 Vue 负责“让数据和界面同步”**。

这种开发方式简单、高效,并且对新手非常友好,容易入门。


🛠️ Vue 独有语法解析:从 $v- 符号开始

Vue 之所以能实现数据驱动,离不开它提供的独有语法,也就是那些带 v- 前缀的 指令(Directives) 和一些特殊符号。

1. 模板插值:双大括号 {{ }}

这是最简单的数据绑定方式,用于将响应式数据的值插入到 HTML 文本内容中。

HTML

<h2>{{title}}</h2>

双大括号内的内容是 JavaScript 表达式,它的结果会被绑定并显示出来。当 title 这个响应式数据改变时,这里的内容也会跟着自动更新

2. Vue 指令(Directives): v-

所有带 v- 前缀的特殊属性都被称为 Vue 指令。它们的作用是:当表达式的值发生变化时,将响应式地作用于 DOM。

A. 列表渲染:v-for 循环输出

v-for 用于基于一个数组来渲染一个列表。它是实现循环输出的最主要方式。

HTML

<ul v-if="todos.length">
    <li v-for="todo in todos" :key="todo.id">
        </li>
</ul>
  • v-for="todo in todos" 遍历 todos 数组,为数组中的每一项数据 todo 渲染一个 <li> 元素。
  • :key="todo.id" 这里的 :key 是一个唯一属性,用于给 Vue 一个提示,以便它能跟踪每个节点的身份。这是 Vue 高效更新列表的关键,强烈建议在使用 v-for 时总是带上 :key,通常使用数据的 ID 作为 Key。

B. 条件渲染:v-if / v-else

v-if 用于根据表达式的布尔值来条件性地渲染元素。

HTML

<ul v-if="todos.length">
    </ul>
<div v-else>
    暂无计划 </div>
  • todos.lengthtrue(大于 0)时,<ul> 标签及其内容才会被渲染到 DOM 中。
  • 当它为 false 时,v-else 所在的 <div> 标签才会被渲染。

C. 表单输入绑定:v-model (双向数据绑定)

v-model 是一个强大的指令,它实现了表单输入元素和应用状态之间的双向数据绑定

HTML

<input type="text" v-model="title" @keydown.enter="addTodo">
<input type="checkbox" v-model="todo.done">
  • 单向绑定: 响应式数据 -> DOM。
  • 双向绑定: 响应式数据 <-> DOM。
  • 当你在输入框中打字时,title 响应式数据会立即更新。
  • 当你点击复选框时,todo.done 响应式数据也会立即更新。
  • Vue 自动完成了我们以前需要 value = ...addEventListener('input', ...) 才能实现的功能。

3. 属性绑定:冒号 : (即 v-bind:)

冒号 :v-bind:缩写,用于将一个 HTML 元素的属性(如 classidhref 等)与一个 JavaScript 表达式的计算结果绑定起来。

HTML

<span :class="{done: todo.done}">{{todo.title}}</span>
  • {done: todo.done} 是一个 JavaScript 对象表达式。
  • 它表示:如果 todo.done 这个响应式数据的值为 true,那么就给当前的 <span> 元素添加一个名为 done 的 CSS 类。
  • 这是实现动态样式、根据数据状态切换属性的关键

4. 事件监听:@ (即 v-on:)

@ 符号是 v-on:缩写,用于监听 DOM 事件,并在事件触发时执行对应的 JavaScript 代码或方法。

HTML

<input type="text" v-model="title" @keydown.enter="addTodo">
  • @keydown.enter 是一个非常友好的 Vue 事件修饰符。它让我们不用在 addTodo 方法里写 if (event.keyCode === 13) 这样的逻辑,Vue 已经帮我们做了。
  • @click@input 等是常用的事件监听。
  • 它替代了我们以前需要手动调用 addEventListener 的复杂操作。

🏗️ Vue 3 核心:Composition API (<script setup>)

上面的代码示例采用的是 Vue 3 推崇的 Composition API(组合式 API)<script setup> 语法糖。

1. <script setup> 的作用

在 Vue 3 中,使用 <script setup> 是一种编译时语法糖,它极大地简化了组件的编写。

  • 作用: 任何在 <script setup> 中声明的变量、函数、导入项,都可以在 <template>直接使用,无需像以前那样手动通过 return 暴露出去。
  • 它让我们的代码更简洁、更集中,也更像原生 JavaScript 的写法。

2. 响应式数据的定义:ref

在 Composition API 中,我们需要使用 refreactive 来创建响应式数据。这里的 ref 起了至关重要的作用。

JavaScript

import { ref } from 'vue';

// 响应式数据
const title = ref("Todos任务清单");
const todos = ref([
    // ... 初始数据
]);
  • ref 的本质: 它将一个原始值(如字符串、数字、布尔值)包装成一个响应式对象
  • 访问/修改数据: 在 JavaScript 代码中,你需要通过 .value 来访问或修改 ref 的值(例如:title.value = '新标题')。
  • 模板中的简化: 但在 <template> 中,Vue 会自动解包 ref,所以你可以直接使用 {{ title }}

总结: ref 就是告诉 Vue:“嘿,我这个数据很重要,你得给我追踪起来,只要它一变,所有用到它的地方(模板)都要自动更新!”

3. 计算属性:computed (性能更好)

计算属性(computed)是 Vue 中一个非常重要的概念,用于处理需要依赖其他响应式数据进行计算得出的值。

JavaScript

import { ref, computed } from 'vue';
// ... todos 数据定义

// 依赖与todos 响应式数据的 计算属性
const active = computed(() => {
    // 计算过程:返回未完成任务的数量
    return todos.value.filter(todo => !todo.done).length; 
});
// 在模板中使用: {{ active }}
  • 形式上是函数(计算过程),结果(计算属性)返回: 你传入的是一个函数,但你在模板或 JS 中使用 active 时,它表现得像一个属性

  • 也是响应式的 依赖于 todos: 因为它依赖于 todos 这个响应式数据,所以当 todos 变化时,active 的值也会自动、实时地更新。

  • 性能更好 (缓存): 这是 computed 最重要的优点!Vue 会对计算属性的结果进行缓存。只有当它所依赖的响应式数据(即 todos)发生变化时,它才会重新计算,否则会直接返回上一次的缓存结果。

    • 相比之下,如果在模板里直接写 {{ todos.filter(...) }},每次组件重新渲染时都会执行一遍计算,性能开销更大。

进阶:带 Setter 的计算属性

计算属性不仅可以读取(get),还可以设置(set),这常用于实现双向操作,比如示例中的“全选”功能:

JavaScript

// computed 高级技巧:实现全选/全不选的逻辑
const allDone = computed({
    // get:读取属性时执行(判断是否所有任务都已完成)
    get() {
        return todos.value.every(todo => todo.done);
    },
    // set:当给这个计算属性赋值时执行(用户点击了全选框)
    set(value) {
        // value 是用户给 allDone 赋的值 (true/false)
        todos.value.forEach(todo => todo.done = value);
    }
});

当你把 v-model 绑定到 allDone 上时:

  1. 用户点击复选框,试图改变 allDone 的值,此时会触发 set(value) 方法。
  2. set 方法修改了 todos 数组中所有任务的 done 状态。
  3. 因为 todos 改变了,所以 get 方法会自动重新计算,allDone 的值也随之更新。

总结:从 DOM 机械师到数据魔术师

通过这个 Todo 任务清单的例子,你应该能深刻感受到 Vue 的开发思路带来的巨大转变:

特性传统 JS 开发(命令式)Vue 开发(声明式/数据驱动)
关注点DOM 元素:getElementByIdinnerHTML响应式数据:reftodos.value
更新方式手动操作 DOM:app.innerHTML = todo自动更新:只需修改数据,Vue 搞定一切
列表渲染字符串拼接,然后 append 到父元素v-for,高效且带 :key 优化
代码效率代码繁琐,大量重复的 DOM 查询和操作简洁高效,聚焦业务逻辑
上手难度前期简单,后期维护难度和复杂度急剧上升前期需学习 Vue 语法,后期开发和维护难度降低

Vue 让我们写的代码质量更好,更容易入门。它提供了 v-for{{ }}ref 等一系列友好的 API,让开发者可以将精力 100% 投入到核心的业务逻辑中

恭喜你,迈出了 Vue 学习的第一步!现在,你不再是一个辛苦的 DOM “机械师”,而是一名优雅高效的**数据“魔术师”**了!