本文详细介绍了Vue3的核心概念、与Vue2的区别、安装配置、基础语法、响应式原理、生命周期、路由与状态管理,并通过实战项目展示了实际应用。文章涵盖了Vue3的各个方面,帮助开发者全面了解和掌握Vue3的使用。
Vue3 是 Vue.js 的最新版本,它引入了许多新特性来改善开发体验和性能。Vue3的核心概念包括但不限于:
setup
函数和 Composition API,实现了更强大的逻辑复用和更清晰的逻辑组织。Vue3 引入了许多新特性和改进,与 Vue2 相比,主要改进包括:
npm install -g @vue/cli
vue create my-vue3-app
cd my-vue3-app npm install
npm run serve
这将启动开发服务器,你可以在浏览器中访问 http://localhost:8080
查看你的 Vue3 项目。
Vue3 的模板语法允许在 HTML 中夹带 Vue 的特殊属性来描述视图。Vue3 的模板语法与 Vue2 非常相似,但引入了一些改进。
使用双大括号表示插值:
<div id="app"> {{ message }} </div>
// main.js import { createApp } from 'vue'; import App from './App.vue'; const app = createApp(App); app.mount('#app');
<!-- App.vue --> <template> <div id="app"> {{ message }} </div> </template> <script> export default { data() { return { message: 'Hello Vue3!' }; } } </script>
Vue3 中有许多指令,如 v-if
、v-for
、v-bind
、v-on
等。
<div v-if="visible">Visible</div> <div v-for="item in items">{{ item }}</div> <a v-bind:href="url">Link</a> <button v-on:click="onClick">Click me</button>
// main.js import { createApp } from 'vue'; import App from './App.vue'; const app = createApp(App); app.mount('#app');
<!-- App.vue --> <template> <div> <div v-if="visible">Visible</div> <div v-for="item in items">{{ item }}</div> <a v-bind:href="url">Link</a> <button v-on:click="onClick">Click me</button> </div> </template> <script> export default { data() { return { visible: true, items: [1, 2, 3], url: 'https://www.example.com' }; }, methods: { onClick() { console.log('Button clicked'); } } } </script>
计算属性是基于它们的依赖缓存的,只有当依赖发生改变时才会重新计算。
<template> <div> <p>原始数据: {{ message }}</p> <p>计算后的数据: {{ reversedMessage }}</p> </div> </template> <script> export default { data() { return { message: 'Hello Vue3!' }; }, computed: { reversedMessage() { return this.message.split('').reverse().join(''); } } } </script>
方法是普通的 JavaScript 函数,会在触发时执行,不会缓存。
<template> <div> <p>{{ message }}</p> <p>{{ reversedMessage() }}</p> <button @click="reverseMessage">Reverse Message</button> </div> </template> <script> export default { data() { return { message: 'Hello Vue3!' }; }, methods: { reversedMessage() { return this.message.split('').reverse().join(''); }, reverseMessage() { this.message = this.message.split('').reverse().join(''); } } } </script>
Vue3 中的组件是自定义的可复用的 Vue 实例,可以像使用 HTML 元素一样在应用中使用。
<!-- Button.vue --> <template> <button @click="onClick">Click me</button> </template> <script> export default { methods: { onClick() { this.$emit('click'); } } } </script>
<!-- App.vue --> <template> <div> <Button v-on:click="handleClick">Click me</Button> </div> </template> <script> import Button from './Button.vue'; export default { components: { Button }, methods: { handleClick() { console.log('Button clicked'); } } } </script>
可以在运行时根据条件动态切换组件。
<template> <div> <button @click="component = 'Button'">Button</button> <button @click="component = 'Input'">Input</button> <component :is="component"></component> </div> </template> <script> import Button from './Button.vue'; import Input from './Input.vue'; export default { components: { Button, Input }, data() { return { component: 'Button' }; } } </script>
Vue3 的响应式系统是其核心特性之一,它允许 Vue 实例自动侦听数据的变化,并更新视图。Vue3 使用了更现代的 JavaScript 语法,如 Proxy,来实现更高效和更灵活的响应式系统。
Vue3 使用 Proxy 代替 Vue2 中的 Object.defineProperty 方法来设置响应式数据。Proxy 可以拦截对对象的任何操作,使 Vue 能够自动追踪数据变化。
const handler = { get(target, key) { console.log(`Reading ${key}`); return target[key]; }, set(target, key, value) { console.log(`Setting ${key} to ${value}`); target[key] = value; } }; const proxy = new Proxy({}, handler); proxy.a = 1; // Setting a to 1 console.log(proxy.a); // Reading a
Vue3 中的数据默认情况下是响应式的,但可以使用 ref
和 reactive
来手动创建响应式对象。
import { ref, reactive } from 'vue'; const count = ref(0); // 使用 ref 创建响应式数据 const state = reactive({ count: 0 }); // 使用 reactive 创建响应式数据
ref
是一个包装器对象,可以用来包装原始值(通常是基本类型),使其能够追踪变化。
import { ref } from 'vue'; const count = ref(0); function increment() { count.value++; } console.log(count.value); // 0 increment(); console.log(count.value); // 1
reactive
可以用来创建一个可监听的对象。
import { reactive } from 'vue'; const state = reactive({ count: 0 }); function increment() { state.count++; } console.log(state.count); // 0 increment(); console.log(state.count); // 1
Vue3 使用 watch
和 computed
来监听数据的变化。
import { ref, watch } from 'vue'; const count = ref(0); watch(count, (newValue, oldValue) => { console.log(`Count changed from ${oldValue} to ${newValue}`); }); count.value++; // Count changed from 0 to 1
计算属性是基于它们的依赖缓存的,只有当依赖发生改变时才会重新计算。
import { ref, computed } from 'vue'; const count = ref(0); const reversedCount = computed(() => { return count.value.split('').reverse().join(''); }); count.value = '12345'; console.log(reversedCount.value); // 54321 count.value = '56789'; console.log(reversedCount.value); // 98765
方法是普通的 JavaScript 函数,会在触发时执行,不会缓存。
import { ref } from 'vue'; const count = ref('12345'); function reverseCount() { return count.value.split('').reverse().join(''); } console.log(reverseCount()); // 54321 count.value = '56789'; console.log(reverseCount()); // 98765
Vue3 提供了一套完整的生命周期钩子,这些钩子允许你在组件的特定阶段执行自定义逻辑。这些钩子包括:
beforeCreate
:在实例初始化之前,可以在此阶段访问 this
,但数据和方法尚未初始化。created
:实例创建完成后,此时数据和方法已初始化,但 DOM 尚未渲染。beforeMount
:组件挂载到 DOM 之前,此时可以访问 this.$el
,但 DOM 尚未渲染。mounted
:组件挂载到 DOM 之后,此时 DOM 已渲染,可以访问 this.$el
。beforeUpdate
:数据更新时触发,此时新数据尚未渲染,可以访问 this.$el
。updated
:数据更新并重新渲染后触发,此时 DOM 已更新。beforeUnmount
:组件卸载之前,此时组件仍然处于 DOM 中。unmounted
:组件完全卸载后触发。
<template> <div> <p>{{ message }}</p> </div> </template>
<script>
export default {
data() {
return {
message: 'Hello Vue3!'
};
},
beforeCreate() {
console.log('beforeCreate');
},
created() {
console.log('created');
},
beforeMount() {
console.log('beforeMount');
},
mounted() {
console.log('mounted');
},
beforeUpdate() {
console.log('beforeUpdate');
},
updated() {
console.log('updated');
},
beforeUnmount() {
console.log('beforeUnmount');
},
unmounted() {
console.log('unmounted');
}
}
</script>
## 生命周期钩子的应用实例 ### 使用生命周期钩子进行数据预处理 可以在 `beforeCreate` 或 `created` 钩子中进行数据预处理。 ```vue <template> <div> <p>{{ message }}</p> </div> </template> <script> export default { data() { return { message: '' }; }, beforeCreate() { console.log('beforeCreate'); fetch('https://api.example.com/data') .then((response) => response.json()) .then((data) => { this.message = data.message; }); }, created() { console.log('created'); } }; </script>
可以在 beforeMount
或 mounted
钩子中进行页面渲染优化,如初始化 DOM 节点。
<template> <div> <p>{{ message }}</p> </div> </template> <script> export default { data() { return { message: '' }; }, beforeMount() { console.log('beforeMount'); }, mounted() { console.log('mounted'); this.$el.style.color = 'red'; } }; </script>
Vue.prototype
中无法使用。beforeUnmount
中注册的监听器,以避免内存泄漏。Vue Router 是 Vue.js 的官方路由管理器,它可以实现应用的路由功能。
npm install vue-router@next
import { createRouter, createWebHistory } from 'vue-router'; import Home from './components/Home.vue'; import About from './components/About.vue'; const routes = [ { path: '/', component: Home }, { path: '/about', component: About } ]; const router = createRouter({ history: createWebHistory(), routes }); export default router;
<!-- App.vue --> <template> <div> <router-link to="/">Home</router-link> <router-link to="/about">About</router-link> <router-view></router-view> </div> </template> <script> import router from './router'; export default { name: 'App', router }; </script>
<!-- Home.vue --> <template> <div> <h1>Home</h1> </div> </template> <script> export default { name: 'Home' }; </script>
<!-- About.vue --> <template> <div> <h1>About</h1> </div> </template> <script> export default { name: 'About' }; </script>
Vuex 是 Vue.js 的官方状态管理库,可以用来实现全局状态管理。
npm install vuex@next
import { createStore } from 'vuex'; const store = createStore({ state: { count: 0 }, mutations: { increment(state) { state.count++; } }, actions: { increment({ commit }) { commit('increment'); } }, getters: { count: state => state.count } }); export default store;
<!-- App.vue --> <template> <div> <p>{{ count }}</p> <button @click="increment">Increment</button> </div> </template> <script> import { mapState, mapActions } from 'vuex'; import store from './store'; export default { store, computed: { ...mapState(['count']) }, methods: { ...mapActions(['increment']) } }; </script>
// store.js import { createStore } from 'vuex'; const store = createStore({ state: { count: 0 }, mutations: { increment(state) { state.count++; } }, actions: { increment({ commit }) { commit('increment'); } }, getters: { count: state => state.count } }); export default store;
<!-- App.vue --> <template> <div> <p>{{ count }}</p> <button @click="increment">Increment</button> </div> </template> <script> import { mapState, mapActions } from 'vuex'; import store from './store'; export default { store, computed: { ...mapState(['count']) }, methods: { ...mapActions(['increment']) } }; </script>
假设我们正在开发一个简单的待办事项应用。需求如下:
vue create todo-app cd todo-app npm install vue-router vuex
todo-app/ ├── src/ │ ├── main.js │ ├── App.vue │ ├── components/ │ │ ├── AddTodo.vue │ │ ├── TodoList.vue │ │ ├── TodoItem.vue │ ├── router/ │ │ ├── index.js │ ├── store/ │ │ ├── index.js │ ├── assets/ │ │ ├── logo.png │ ├── styles/ │ │ ├── App.css ├── package.json └── README.md
<template> <div> <input v-model="newTodo" @keyup.enter="addTodo" placeholder="Add a new todo"> </div> </template> <script> export default { data() { return { newTodo: '' }; }, methods: { addTodo() { if (this.newTodo.trim()) { this.$store.commit('addTodo', this.newTodo); this.newTodo = ''; } } } }; </script>
<template> <div> <ul> <TodoItem v-for="todo in todos" :key="todo.id" :todo="todo" /> </ul> </div> </template> <script> import TodoItem from './TodoItem.vue'; export default { components: { TodoItem }, computed: { todos() { return this.$store.getters.todos; } } }; </script>
<template> <li :class="{ completed: todo.completed }"> <input type="checkbox" v-model="todo.completed"> <span>{{ todo.text }}</span> <button @click="removeTodo">Delete</button> </li> </template> <script> export default { props: ['todo'], methods: { removeTodo() { this.$store.commit('removeTodo', this.todo.id); } } }; </script>
// store/index.js import { createStore } from 'vuex'; const store = createStore({ state: { todos: [] }, mutations: { addTodo(state, todo) { state.todos.push({ id: Date.now(), text: todo, completed: false }); }, removeTodo(state, id) { state.todos = state.todos.filter(todo => todo.id !== id); } }, actions: { addTodo({ commit }, todo) { commit('addTodo', todo); }, removeTodo({ commit }, id) { commit('removeTodo', id); } }, getters: { todos: state => state.todos } }); export default store;
console.log
语句来调试应用。npm run build
这将生成 dist
目录,里面包含了构建好的 HTML、CSS 和 JavaScript 文件。
dist
目录中的所有文件上传到你的服务器,确保服务器支持静态文件托管。dist
目录中的文件上传到 CDN,并在服务器上配置相应的路径。通过以上步骤,你可以完成一个简单的待办事项应用的开发、调试和部署。