别再手动操作 DOM 了!Vue3 让你用“意念”操控 TodoList(附赠摸鱼技巧)

36 阅读3分钟

“我写 JS 就是为了不写 JS。”


🧠 从前,我们这样写 TodoList...

还记得刚学前端时,你是怎么实现一个简单的待办事项(TodoList)的吗?

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;
});

是不是感觉像在给浏览器“下命令”?
先找元素 → 再监听事件 → 然后改内容 → 最后祈祷别出 bug。

这种命令式编程,就像你对机器人说:“去厨房,打开冰箱,拿出可乐,拧开瓶盖,倒进杯子,端给我。”
而 Vue 想说的是: “我要喝可乐。” ——剩下的,它来搞定。


✨ Vue 的哲学:数据驱动一切

Vue 的核心思想就一句话:

“你只管关心数据怎么变,DOM 怎么更新?那是我的事。”

这叫 响应式数据驱动
你不再需要思考“怎么改页面”,而是思考“数据应该变成什么样”。

比如:

  • 用户输入新任务 → todos 数组加一项
  • 勾选完成 → 对应 done 变成 true
  • 全选 → 所有 done 都设为 true

DOM 自动跟着变,连 CSS 动画都省了!


🧪 Vue3 Composition API:更清爽的代码体验

Vue3 引入了 Composition API(组合式 API),让逻辑组织更清晰、复用更容易。

来看一个标准的 TodoList 组件骨架:

<script setup>
import { ref, computed } from 'vue'

// 响应式数据
const title = ref('')
const todos = ref([
  { id: 1, title: '打王者', done: false },
  { id: 2, title: '吃饭', done: false }
])

// 添加任务
const addTodo = () => {
  if (!title.value.trim()) return
  todos.value.push({
    id: Math.random(),
    title: title.value,
    done: false
  })
  title.value = ''
}

// 计算属性:未完成数量
const active = computed(() => 
  todos.value.filter(todo => !todo.done).length
)

// 全选/反选(带 getter/setter 的 computed)
const allDone = computed({
  get() {
    return todos.value.length > 0 && todos.value.every(t => t.done)
  },
  set(val) {
    todos.value.forEach(t => t.done = val)
  }
})
</script>

是不是比 document.getElementById 清爽一百倍?
而且逻辑集中、变量明确、复用方便——这才是现代前端该有的样子!


🔥 关键指令速览:Vue 的“魔法咒语”

指令作用类比
v-model双向绑定输入框“你打字,我自动记下来”
v-for循环渲染列表“有多少数据,我就画多少行”
v-if / v-else条件渲染“没任务?那我就躺平显示‘暂无计划’”
@keydown.enter监听回车“按回车?懂了,马上加任务!”
:class动态样式“完成的任务?灰掉+删除线,安排!”

这些指令,本质上就是 Vue 给你封装好的“快捷操作包”。
你不用再写 element.classList.add('done'),只需一句:

<span :class="{ done: todo.done }">{{ todo.title }}</span>

优雅,永不过时。


💡 computed:性能优化的秘密武器

很多人以为 computed 只是“把函数结果缓存一下”,其实它更厉害:

  • 依赖追踪:只有依赖的数据变了,才重新计算。
  • 自动缓存:多次访问不会重复执行。
  • 支持 setter:可以反向修改原始数据(比如全选功能)。

比如这个 active

const active = computed(() => 
  todos.value.filter(todo => !todo.done).length
)

即使你在模板里写了十次 {{ active }},它也只算一次。
而如果你直接写 {{ todos.filter(...).length }},每次渲染都会重新过滤——性能杀手!


🎨 模板长这样(简洁又强大)

<template>
  <div>
    <h2>{{ title }}</h2>
    <input v-model="title" @keydown.enter="addTodo" placeholder="输入任务,回车添加">

    <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>
      <label>
        <input type="checkbox" v-model="allDone"> 全选
      </label>
      {{ active }} / {{ todos.length }}
    </div>
  </div>
</template>

<style scoped>
.done {
  color: gray;
  text-decoration: line-through;
}
</style>

短短几十行,完成了:

  • 输入回车添加
  • 列表渲染
  • 完成状态切换
  • 全选/反选
  • 实时统计
  • 样式联动

这效率,老板看了想加薪,同事看了想抄代码。


🤔 为什么 Vue 更适合新手?

  1. 降低心智负担:不用记 DOM API,专注业务逻辑。
  2. 错误更少:避免手误拼错 getElementById
  3. 开发更快:声明式语法,所见即所得。
  4. 调试更爽:DevTools 直接看响应式数据变化。

就像你不需要会造汽车,也能开车上路。Vue 就是你的“自动驾驶系统”。


🚀 结语:从“操作 DOM”到“操控数据”

传统开发: “我要让那个 div 变红!”
Vue 开发: “这个状态是 error,UI 自己知道该怎么做。”

真正的前端高手,不是 DOM 操作多熟练,而是能把复杂逻辑抽象成清晰的数据流。

所以,下次写 TodoList 时,别再 querySelector 了。
打开 Vue,写一行 ref,剩下的——交给框架,你去摸鱼。

毕竟,程序员的终极目标,是让代码自己干活。