🚀 从DOM操作到Vue3:一个Todo应用的思维革命

🚀 从DOM操作到Vue3:一个Todo应用的思维革命

前言 :当我第一次学习前端时,导师让我实现一个Todo应用。我花了2小时写了50行代码,导师看了一眼说:"试试Vue3吧。" 我用30分钟重写了同样的功能,代码减少到20行。那一刻,我明白了什么是真正的数据驱动开发。今天,我想通过这个Todo应用,带你体验这场思维革命。

第一章:传统开发方式的困境

让我们先回顾一下用原生JavaScript实现的Todo应用:

html 复制代码
<!-- demo.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>传统Todo应用</title>
</head>
<body>
    <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
            }
            // 手动更新DOM
            app.innerHTML = todo
        })
    </script>
</body>
</html>

🔍 传统方式的三大痛点:

  1. 命令式编程:你需要像指挥官一样告诉浏览器每一步该做什么
  2. DOM操作繁琐:每次数据变化都要手动查找和更新DOM
  3. 关注点错位:80%的代码在处理界面操作,只有20%在处理业务逻辑

这就像每次想改变房间布局,都要亲自搬砖砌墙

第二章:Vue3的数据驱动革命

现在,让我们看看用Vue3实现的完整Todo应用:

vue 复制代码
<!-- App.vue -->
<template>
  <div>
    <!-- 1. 数据绑定 -->
    <h2>{{title}}</h2>
    
    <!-- 2. 双向数据绑定 -->
    <input 
      type="text" 
      v-model="title" 
      @keydown.enter="addTodo"
      placeholder="输入任务后按回车"
    >
    
    <!-- 3. 条件渲染 -->
    <ul v-if="todos.length">
      <!-- 4. 列表渲染 -->
      <li v-for="todo in todos" :key="todo.id">
        <!-- 5. 双向绑定到对象属性 -->
        <input type="checkbox" v-model="todo.done">
        
        <!-- 6. 动态class绑定 -->
        <span :class="{done: todo.done}">{{todo.title}}</span>
      </li>
    </ul>
    
    <!-- 7. v-else指令 -->
    <div v-else>
      暂无任务
    </div>
    
    <!-- 8. 计算属性使用 -->
    <div>
      进度:{{activeTodos}} / {{todos.length}}
    </div>
    
    <!-- 9. 计算属性的getter/setter -->
    全选<input type="checkbox" v-model="allDone">
  </div>
</template>

<script setup>
// 10. Composition API导入
import { ref, computed, watch } from 'vue'

// 11. 响应式数据
const title = ref("Todos任务清单")
const todos = ref([
  {
    id: 1,
    title: '学习vue',
    done: false
  },
  {
    id: 2,
    title: '打王者',
    done: false
  },
    {
    id: 3,
    title: '吃饭',
    done: true
  }
])

// 12. 计算属性
const activeTodos = computed(() => {
  return todos.value.filter(todo => !todo.done).length
})

// 13. 方法定义
const addTodo = () => {
  if(!title.value) return
  
  todos.value.push({
    id: Date.now(),  // 更好的ID生成方式
    title: title.value,
    done: false
  })
  
  title.value = ""
}

// 14. 计算属性的getter/setter
const allDone = computed({
  get() {
    return todos.value.length > 0 && 
           todos.value.every(todo => todo.done)
  },
  set(val) {
    todos.value.forEach(todo => todo.done = val)
  }
})

// 15. 监听器 - 补充知识点
watch(todos, (newTodos) => {
  console.log('任务列表发生变化:', newTodos)
  // 可以在这里实现本地存储
}, { deep: true })

// 16. 生命周期钩子 - 补充知识点
import { onMounted } from 'vue'
onMounted(() => {
  console.log('组件挂载完成')
  // 可以在这里从本地存储读取数据
})
</script>

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

/* 17. 组件样式作用域 - 补充知识点 */
/* 这里的样式只作用于当前组件 */
</style>

第三章:Vue3核心API深度解析

🎯 1. ref - 响应式数据的基石

代码:

javascript 复制代码
const title = ref("Todos任务清单")

补充:

  • ref用于创建响应式引用
  • 访问值需要使用.value
  • 为什么需要.value?因为Vue需要知道哪些数据需要被追踪变化
javascript 复制代码
// ref的内部原理简化版
function ref(initialValue) {
  let value = initialValue
  return {
    get value() {
      // 这里可以收集依赖
      return value
    },
    set value(newValue) {
      value = newValue
      // 这里可以通知更新
    }
  }
}

🎯 2. v-model - 双向绑定的魔法

代码:

html 复制代码
<input type="text" v-model="title">

补充: v-model实际上是语法糖,它等于:

html 复制代码
<input 
  :value="title"
  @input="title = $event.target.value"
>

对于复选框,v-model的处理有所不同:

html 复制代码
<input type="checkbox" v-model="todo.done">
<!-- 等价于 -->
<input 
  type="checkbox" 
  :checked="todo.done"
  @change="todo.done = $event.target.checked"
>

🎯 3. 指令系统详解

v-show vs v-if

vue 复制代码
<!-- v-if是真正的条件渲染 -->
<div v-if="show">条件渲染</div> <!-- 会从DOM中移除/添加 -->

<!-- v-show只是控制display -->
<div v-show="show">显示控制</div> <!-- 始终在DOM中,只是display切换 -->

动态参数

vue 复制代码
<!-- 动态指令参数 -->
<a :[attributeName]="url">链接</a>
<button @[eventName]="doSomething">按钮</button>

🎯 4. computed - 智能计算属性

细节

javascript 复制代码
// 计算属性的缓存特性
const expensiveCalculation = computed(() => {
  console.log('重新计算') // 只有依赖变化时才会执行
  return todos.value
    .filter(todo => !todo.done)
    .map(todo => todo.title.toUpperCase())
    .join(', ')
})

// 依赖没有变化时,直接返回缓存值
console.log(expensiveCalculation.value) // 输出并打印"重新计算"
console.log(expensiveCalculation.value) // 直接返回缓存值,不打印

🎯 5. watch - 数据监听器

重要知识点:

javascript 复制代码
// 1. 监听单个ref
watch(title, (newTitle, oldTitle) => {
  console.log(`标题从"${oldTitle}"变为"${newTitle}"`)
})

// 2. 监听多个数据源
watch([title, todos], ([newTitle, newTodos], [oldTitle, oldTodos]) => {
  // 处理变化
})

// 3. 立即执行的watch
watch(todos, (newTodos) => {
  localStorage.setItem('todos', JSON.stringify(newTodos))
}, { immediate: true }) // 组件创建时立即执行一次

// 4. 深度监听
watch(todos, (newTodos) => {
  // 可以检测到对象内部属性的变化
}, { deep: true })

🎯 6. 生命周期钩子

完整生命周期:

javascript 复制代码
import { 
  onBeforeMount, 
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted,
  onErrorCaptured
} from 'vue'

onBeforeMount(() => {
  console.log('组件挂载前')
})

onMounted(() => {
  console.log('组件已挂载,可以访问DOM')
})

onBeforeUpdate(() => {
  console.log('组件更新前')
})

onUpdated(() => {
  console.log('组件已更新')
})

onBeforeUnmount(() => {
  console.log('组件卸载前')
})

onUnmounted(() => {
  console.log('组件已卸载')
})

onErrorCaptured((error) => {
  console.error('捕获到子组件错误:', error)
})

第四章:Vue3开发模式的优势

🚀 1. 开发效率对比

功能 传统JS代码量 Vue3代码量 效率提升
数据绑定 10-15行 1行 90%
列表渲染 15-20行 3行 85%
事件处理 5-10行 1行 80%
样式绑定 5-10行 1行 80%

🎯 2. 思维模式转变

传统开发思维(怎么做):

markdown 复制代码
1. 找到DOM元素
2. 监听事件
3. 获取数据
4. 操作DOM更新界面

Vue3开发思维(要什么):

markdown 复制代码
1. 定义数据状态
2. 描述UI与数据的关系
3. 修改数据
4. 界面自动更新

💡 3. 性能优化自动化

Vue3自动为你做了这些优化:

javascript 复制代码
// 1. 虚拟DOM减少真实DOM操作
// 2. Diff算法最小化更新
// 3. 响应式系统精确追踪依赖
// 4. 计算属性缓存避免重复计算
// 5. 组件复用减少渲染开销

第五章:实战技巧与最佳实践

📝 1. 代码组织建议

vue 复制代码
<script setup>
// 1. 导入部分
import { ref, computed, watch, onMounted } from 'vue'

// 2. 响应式数据
const title = ref('')
const todos = ref([])

// 3. 计算属性
const activeCount = computed(() => { /* ... */ })

// 4. 方法定义
const addTodo = () => { /* ... */ }

// 5. 生命周期
onMounted(() => { /* ... */ })

// 6. 监听器
watch(todos, () => { /* ... */ })
</script>

🎨 2. 样式管理技巧

vue 复制代码
<style scoped>
/* scoped属性让样式只作用于当前组件 */
.todo-item {
  padding: 10px;
}

/* 深度选择器 */
:deep(.child-component) {
  color: red;
}

/* 全局样式 */
:global(.global-class) {
  font-size: 16px;
}
</style>

🔧 3. 调试技巧

javascript 复制代码
// 1. 在模板中调试
<div>{{ debugInfo }}</div>

// 2. 使用Vue Devtools浏览器插件
// 3. 使用console.log增强
watch(todos, (newTodos) => {
  console.log('todos变化:', JSON.stringify(newTodos, null, 2))
}, { deep: true })

结语:从学习者到实践者

通过这个Todo应用,我们看到了Vue3如何将我们从繁琐的DOM操作中解放出来,让我们能更专注于业务逻辑。这种声明式编程的思维方式,不仅让代码更简洁,也让开发更高效。

记住

  1. Vue3不是魔法,但它让开发变得像魔法一样简单
  2. 学习Vue3不仅是学习一个框架,更是学习一种更好的编程思维
  3. 从今天开始,尝试用数据驱动的方式思考问题

下一步建议

  1. 在Vue Playground中多练习
  2. 阅读Vue3官方文档
  3. 尝试实现更复杂的功能(过滤、搜索、排序)
  4. 学习Vue Router和Pinia

📚 资源推荐

希望这篇文章能帮助你更好地理解Vue3的强大之处!如果你有任何问题或想法,欢迎在评论区讨论交流。🌟

一起进步,从今天开始!

相关推荐
未来龙皇小蓝9 小时前
RBAC前端架构-02:集成Vue Router、Vuex和Axios实现基本认证实现
前端·vue.js·架构
晓得迷路了9 小时前
栗子前端技术周刊第 116 期 - 2025 JS 状态调查结果、Babel 7.29.0、Vue Router 5...
前端·javascript·vue.js
淡忘_cx9 小时前
使用Jenkins自动化部署vue项目(2.528.2版本)
vue.js·自动化·jenkins
iDao技术魔方9 小时前
深入Vue 3响应式系统:为什么嵌套对象修改后界面不更新?
javascript·vue.js·ecmascript
念念不忘 必有回响9 小时前
viepress:vue组件展示和源码功能
前端·javascript·vue.js
吹牛不交税20 小时前
admin.net-v2 框架使用笔记-netcore8.0/10.0版
vue.js·.netcore
MZ_ZXD00121 小时前
springboot旅游信息管理系统-计算机毕业设计源码21675
java·c++·vue.js·spring boot·python·django·php
_codemonster1 天前
Vue的三种使用方式对比
前端·javascript·vue.js
wqq63108551 天前
Python基于Vue的实验室管理系统 django flask pycharm
vue.js·python·django