记得那些年我们写Vue代码的标准开场白吗?没错,就是那个熟悉的new Vue({...})。这行代码就像老朋友一样,陪伴我们度过了无数个撸码的夜晚。但就在Vue 3.0横空出世后,这个老朋友突然宣布“退休”了!
一、Vue 2时代的“初恋回忆”
先来一波回忆杀。在Vue 2.x版本中,我们是这样开启一个Vue应用的:
// Vue 2.x 经典写法
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
},
methods: {
showMessage: function() {
alert(this.message)
}
}
})
这种基于构造函数的写法,就像买奶茶时固定搭配的“标准糖”——简单直接,但缺乏灵活性。所有的选项(data、methods、computed等)都必须塞进一个巨大的配置对象里,随着项目规模扩大,这个对象会变得越来越臃肿。
更让人头疼的是逻辑复用。想象一下,当多个组件需要相同的逻辑时,我们只能通过mixin来实现。但mixin就像把不同颜色的橡皮泥混在一起——最终你会得到一块不知道是什么颜色的新橡皮泥(命名冲突、来源不明确等问题)!
二、Vue 3.0的“革命性转变”
那么Vue 3.0带来了什么变化呢?最直观的就是——没有new了!
// Vue 3.x 新写法
import { createApp } from 'vue'
const app = createApp({
data() {
return {
message: 'Hello Vue 3!'
}
},
methods: {
showMessage() {
alert(this.message)
}
}
})
app.mount('#app')
看到区别了吗?我们不再使用new关键字,而是通过createApp函数来创建应用实例。这不仅仅是语法上的改变,更是编程思维的重大转变。
为什么要有这个变化? 背后的原因其实很实在:
- 更好的Tree-shaking支持:函数式导入让打包工具能更准确地识别未使用的代码
- 多实例管理:可以创建多个独立的Vue应用实例而互不干扰
- 更好的TypeScript支持:函数比类具有更友好的类型推断
- 逻辑组合能力:为组合式API(Composition API)铺平道路
三、组合式API:Vue 3的“灵魂伴侣”
如果说取消构造函数是Vue 3的外在变化,那么组合式API就是其内在灵魂。让我们通过一个实际例子来感受这种变化:
Vue 2选项式API写法:
// Vue 2.x - 选项式API
export default {
data() {
return {
count: 0,
searchQuery: '',
searchResults: []
}
},
computed: {
filteredResults() {
return this.searchResults.filter(item =>
item.title.includes(this.searchQuery)
)
}
},
methods: {
increment() {
this.count++
},
async search() {
this.searchResults = await fetchResults(this.searchQuery)
}
},
mounted() {
this.search()
}
}
Vue 3组合式API写法:
// Vue 3.x - 组合式API
import { ref, computed, onMounted } from 'vue'
export default {
setup() {
// 计数器逻辑
const count = ref(0)
const increment = () => {
count.value++
}
// 搜索逻辑
const searchQuery = ref('')
const searchResults = ref([])
const filteredResults = computed(() => {
return searchResults.value.filter(item =>
item.title.includes(searchQuery.value)
)
})
const search = async () => {
searchResults.value = await fetchResults(searchQuery.value)
}
onMounted(() => {
search()
})
return {
count,
increment,
searchQuery,
filteredResults,
search
}
}
}
看到组合式API的优势了吗?相关的逻辑现在被组织在一起,而不是分散在不同的选项中。这就像从“按功能分类的文件夹”变成了“按项目分类的文件夹”——找东西更方便了!
四、完整示例:打造一个Vue 3待办清单应用
理论说再多不如实战来得实在。下面我们用一个完整的待办清单应用来展示Vue 3的新特性:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Vue 3待办清单</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<style>
.todo-app { max-width: 400px; margin: 20px auto; }
.todo-item { display: flex; align-items: center; margin: 10px 0; }
.completed { text-decoration: line-through; color: #888; }
.fade-enter-active, .fade-leave-active { transition: opacity 0.5s; }
.fade-enter, .fade-leave-to { opacity: 0; }
</style>
</head>
<body>
<div id="app"></div>
<script>
const { createApp, ref, computed, onMounted } = Vue;
// 独立可复用的逻辑函数
function useTodoList() {
const todos = ref([]);
const newTodo = ref('');
const addTodo = () => {
if (newTodo.value.trim()) {
todos.value.push({
id: Date.now(),
text: newTodo.value.trim(),
completed: false
});
newTodo.value = '';
}
};
const removeTodo = (id) => {
todos.value = todos.value.filter(todo => todo.id !== id);
};
const toggleTodo = (id) => {
const todo = todos.value.find(todo => todo.id === id);
if (todo) todo.completed = !todo.completed;
};
// 自动保存到localStorage
const saveToLocalStorage = () => {
localStorage.setItem('vue3-todos', JSON.stringify(todos.value));
};
// 从localStorage加载
onMounted(() => {
const saved = localStorage.getItem('vue3-todos');
if (saved) {
todos.value = JSON.parse(saved);
}
});
return {
todos,
newTodo,
addTodo,
removeTodo,
toggleTodo,
saveToLocalStorage
};
}
// 统计逻辑
function useTodoStats(todos) {
const total = computed(() => todos.value.length);
const completed = computed(() =>
todos.value.filter(todo => todo.completed).length
);
const pending = computed(() => total.value - completed.value);
return {
total,
completed,
pending
};
}
// 创建Vue应用
const app = createApp({
setup() {
const { todos, newTodo, addTodo, removeTodo, toggleTodo } = useTodoList();
const { total, completed, pending } = useTodoStats(todos);
// 搜索功能
const searchQuery = ref('');
const filteredTodos = computed(() => {
if (!searchQuery.value) return todos.value;
return todos.value.filter(todo =>
todo.text.toLowerCase().includes(searchQuery.value.toLowerCase())
);
});
return {
todos: filteredTodos,
newTodo,
addTodo,
removeTodo,
toggleTodo,
searchQuery,
total,
completed,
pending
};
},
template: `
<div class="todo-app">
<h1>Vue 3待办清单 🎯</h1>
<div class="stats">
<p>总计: {{total}} | 完成: {{completed}} | 待办: {{pending}}</p>
</div>
<div class="search">
<input
v-model="searchQuery"
placeholder="搜索待办事项..."
class="search-input"
>
</div>
<div class="add-todo">
<input
v-model="newTodo"
@keyup.enter="addTodo"
placeholder="添加新待办事项..."
class="todo-input"
>
<button @click="addTodo">添加</button>
</div>
<transition-group name="fade" tag="div" class="todo-list">
<div v-for="todo in todos" :key="todo.id" class="todo-item">
<input
type="checkbox"
:checked="todo.completed"
@change="toggleTodo(todo.id)"
>
<span
:class="{ completed: todo.completed }"
@dblclick="toggleTodo(todo.id)"
>
{{todo.text}}
</span>
<button @click="removeTodo(todo.id)" class="delete-btn">删除</button>
</div>
</transition-group>
<div v-if="todos.length === 0" class="empty-state">
🎉 没有待办事项!享受你的空闲时间吧!
</div>
</div>
`
});
app.mount('#app');
</script>
</body>
</html>
这个示例展示了Vue 3的几个核心优势:
- 逻辑复用:
useTodoList和useTodoStats可以轻松在其他组件中复用 - 更好的类型推断:所有变量都有明确的类型
- 灵活的代码组织:相关逻辑集中在一起,易于维护
- 响应式系统升级:基于Proxy的响应式系统提供更好的性能
五、迁移指南:从Vue 2到Vue 3
如果你有现有的Vue 2项目,迁移到Vue 3并不复杂:
安装Vue 3:
npm install vue@next
更新main.js:
// 之前 (Vue 2)
import Vue from 'vue'
import App from './App.vue'
new Vue({
render: h => h(App)
}).$mount('#app')
// 之后 (Vue 3)
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
渐进式迁移:可以在同一个项目中同时使用选项式API和组合式API
六、总结:拥抱变化,享受更好的开发体验
Vue 3取消构造函数不仅仅是一个语法变化,它代表着前端开发范式的演进。从面向对象的类思维转向函数式编程思维,这种变化带来了:
- 更好的代码组织:逻辑关注点集中,不再碎片化
- 更强的类型支持:TypeScript开发体验大幅提升
- 更小的打包体积:Tree-shaking让未使用的代码自动消除
- 更高的性能:基于Proxy的响应式系统性能更优
虽然学习曲线存在,但投资时间学习Vue 3绝对是值得的。就像从功能手机切换到智能手机一样,一开始可能会有些不习惯,但一旦适应,你就再也回不去了!
现在,是时候对你的Vue代码说一句:“嘿,我们换个新的写法吧!” 🚀

被折叠的 条评论
为什么被折叠?



