第十章:Vue的温柔陷阱——渐进式的魅力

“React 和 Angular 打架的时候,Vue 悄悄偷走了开发者的心。”

林小凡第一次听说 Vue,是在某个深夜的技术论坛上。

当时他正深陷 React 的 useEffect 依赖数组地狱,而隔壁工位的同事却哼着小曲,愉快地敲着键盘,屏幕上的代码简洁得像一首诗:

html 复制代码
<template>
  <div>
    <h1>{{ message }}</h1>
    <button @click="reverseMessage">翻转</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: 'Hello Vue!'
    }
  },
  methods: {
    reverseMessage() {
      this.message = this.message.split('').reverse().join('')
    }
  }
}
</script>

<style scoped>
h1 {
  color: #42b983;
}
</style>

“这……这也太简单了吧?!”林小凡瞪大眼睛,仿佛看到了前端世界的乌托邦。


第一节:渐进式的诱惑

Vue 的宣传语是**“渐进式框架”**,而林小凡很快明白了它的含义。

他接手的第一个 Vue 项目,竟然是从一个 jQuery 老系统逐步迁移过来的。

原来的代码:

html 复制代码
<!-- 旧版jQuery页面 -->
<div id="app">
  <div class="header"></div>
  <div class="content">
    <!-- 一堆DOM操作 -->
  </div>
</div>
<script src="jquery.min.js"></script>
<script src="legacy.js"></script>

迁移的第一步,仅仅是在页面底部加了一行:

html 复制代码
<!-- 引入Vue -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>

然后,在某个角落慢慢替换:

javascript 复制代码
// 渐进式改造
new Vue({
  el: '#header',
  data: {
    title: '新版Vue头部'
  },
  template: `<div>{{ title }}</div>`
})

“居然不用重写整个项目?!”林小凡震惊了,“React 可是要求全盘推翻啊!”

墨尘发来一个微笑表情:

“这就是 Vue 的温柔陷阱——它从不强迫你革命,而是邀请你改良。”


第二节:单文件组件的优雅

当林小凡第一次打开 .vue 文件时,他仿佛听到了天使的合唱。

html 复制代码
<template>
  <!-- HTML模板 -->
</template>

<script>
  // JavaScript逻辑
</script>

<style scoped>
  /* 只作用于本组件的CSS */
</style>

对比 React 的 JSX + CSS-in-JS 方案:

jsx 复制代码
function Component() {
  const [state, setState] = useState();
  return (
    <div css={/* 样式对象 */}>
      {/* 逻辑和UI混合 */}
    </div>
  );
}

“这才是我想要的关注点分离!”林小凡热泪盈眶。

直到他尝试在 Vue 里写一个复杂逻辑:

html 复制代码
<script>
export default {
  data() {
    return { count: 0 }
  },
  computed: {
    doubleCount() {
      return this.count * 2
    }
  },
  watch: {
    count(newVal) {
      console.log(`计数变化:${newVal}`)
    }
  },
  methods: {
    increment() {
      this.count++
    }
  },
  created() {
    console.log('组件诞生!')
  }
}
</script>

“等等……data 要写成函数返回对象?methodscomputed 为什么要分开?”

墨尘的回复一针见血:

“Vue 的约定大于配置——听话就有糖吃,叛逆就吃警告。”


第三节:响应式的魔法与诅咒

Vue 最让林小凡着迷的是它的响应式系统。

简单到令人发指的数据驱动:

javascript 复制代码
data() {
  return {
    user: {
      name: '林小凡',
      skills: ['JS', 'CSS']
    }
  }
}

然后在模板里:

html 复制代码
<p>{{ user.name }}</p>
<ul>
  <li v-for="skill in user.skills" :key="skill">{{ skill }}</li>
</ul>

修改数据时,UI 自动更新

javascript 复制代码
this.user.name = '大凡' // 视图同步变化
this.user.skills.push('Vue') // 数组也能响应!

“这才叫双向绑定!Angular 那个$scope太丑了!”林小凡兴奋地大喊。

直到他遇到这个情况:

javascript 复制代码
this.user.skills[0] = 'JavaScript' // 视图不更新!
this.user.age = 25 // 新属性不响应!

解决方案是:

javascript 复制代码
this.$set(this.user.skills, 0, 'JavaScript') // 特殊API
this.$set(this.user, 'age', 25) // 还是特殊API

“说好的‘渐进式’呢?!”林小凡摔键盘,“这明明是‘渐进式坑爹’!”


第四节:Vuex 的状态迷宫

当项目复杂度上升,林小凡不得不引入 Vuex。

对比 Redux 的繁琐,Vuex 看起来简单多了:

javascript 复制代码
// store.js
export default new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      state.count++
    }
  },
  actions: {
    asyncIncrement({ commit }) {
      setTimeout(() => commit('increment'), 1000)
    }
  },
  getters: {
    doubleCount: state => state.count * 2
  }
})

组件中使用:

javascript 复制代码
computed: {
  ...mapState(['count']),
  ...mapGetters(['doubleCount'])
},
methods: {
  ...mapMutations(['increment']),
  ...mapActions(['asyncIncrement'])
}

“这语法糖甜到掉牙了!”林小凡刚赞叹完,就发现项目里出现了:

  • this.$store.state.moduleA.moduleB.data
  • 嵌套五层的namespaced模块
  • 同时存在mutationsactions的异步地狱

墨尘发来一个悲伤的表情:

“所有状态管理方案,最终都会变成你看不懂的样子。”


第五节:Vue 3 的颠覆

当林小凡刚熟悉 Vue 2,Vue 3 带着 Composition API 杀到了:

html 复制代码
<script setup>
import { ref, computed, onMounted } from 'vue'

const count = ref(0)
const doubleCount = computed(() => count.value * 2)

function increment() {
  count.value++
}

onMounted(() => {
  console.log('组件挂载!')
})
</script>

“这……这不是在模仿 React Hooks 吗?!”林小凡三观碎裂。

更冲击的是,Vue 3 的响应式系统完全重写:

javascript 复制代码
import { reactive } from 'vue'

const obj = reactive({ a: 1 })

obj.a = 2 // 现在连数组索引和新增属性都响应了!

“所以 Vue 2 的$set是历史包袱?”他忽然理解了技术演进的残酷。


终节:温柔的代价

某个深夜,林小凡在 GitHub 上看到尤雨溪早期的一段采访:

“Vue 的设计理念是降低前端开发的门槛。”

他看了看自己写的 Vue 代码,又看了看旁边 React 项目的useMemo依赖数组,忽然明白了 Vue 的“温柔陷阱”——

它用最亲切的方式带你进门,但当你想攀登高峰时,会发现:

所有框架,最终都会同样复杂。

窗外,月光照在并排打开的三个文档上:

  • Vue 2 Options API
  • Vue 3 Composition API
  • React Hooks

像三个时代的墓碑,又像三扇通向未来的门。

第十章 完


下一章预告:
第十一章:框架选型的十字路口——技术栈的抉择
“当技术Leader说‘我们选型要考虑未来’时,真正的意思是‘我昨天刚看了这个框架的发布会’。”——某被迫迁移三次的技术团队