Vue3是Vue.js的最新版本,带来了Composition API、Teleport等新特性,提升了性能和易用性。本文将详细介绍Vue3的环境搭建、基础语法、响应式系统、路由与状态管理,并通过一个简单的待办事项应用实战,帮助读者掌握Vue3的开发技巧。
Vue 3 是 Vue.js 的最新版本,带来了许多新特性以提高性能、易用性和可维护性。以下是一些主要的新特性:
<teleport>
元素允许模板的一部分在 DOM 中的任何位置渲染,而不仅仅是在组件的挂载点。为了开始构建 Vue 3 项目,你需要首先安装 Node.js。你可以从Node.js官网下载并安装最新版本。
# 查看是否已安装 node -v # 安装Node.js # 假设使用的是Node.js官网提供的安装包 # https://nodejs.org/en/download/ # 安装完成后,验证安装 node -v
接下来,你需要安装 Vue CLI,它是一个命令行工具,用于快速搭建 Vue.js 项目。
# 安装Vue CLI npm install -g @vue/cli # 验证Vue CLI是否安装成功 vue --version
安装完 Vue CLI 后,你可以通过以下步骤创建一个新的 Vue 3 项目:
# 创建一个新项目 vue create my-vue3-app # 在项目创建过程中,选择 Vue 3 模板 # 通过yarn或npm创建项目 cd my-vue3-app npm run serve
在 vue create my-vue3-app
过程中,选择 Vue 3 模板。你需要在命令行中按下 y
键选择 Vue 3 模板。示例如下:
Vue CLI 4.5.9 ? Please pick a preset (Use arrow keys) ❯ Default ([vue-cli-plugin-vue2] babel, router, vue-loader) Default (Vue 3) (babel, router, vue-loader) Manually select features
选择 Default (Vue 3)
模板以后,继续完成其他配置即可。
这将创建一个基本的 Vue 3 项目结构,并启动开发服务器。你可以在浏览器中访问 http://localhost:8080
查看你的项目。
Vue 3 使用模板语法来构建用户界面,类似于 HTML,但它扩展了一些特性来更好地管理状态和事件。以下是一些常用的模板语法示例:
<!-- 安全转义输出 --> <p>{{ message }}</p> <!-- 原样输出 --> <p v-html="rawMessage"></p> <!-- 条件渲染 --> <div v-if="ok">Yes</div> <div v-else>No</div> <!-- 列表渲染 --> <ul> <li v-for="item in items" :key="item.id">{{ item }}</li> </ul> <!-- 事件处理 --> <button v-on:click="incrementCount">加一</button> <!-- 修饰符 --> <button v-on:click.ctrl="onCtrlClick">Ctrl+Click</button>
Vue 3 中,组件是构建复杂用户界面的基础。以下是如何定义和注册组件的示例:
// 定义一个Vue组件 const MyComponent = { data() { return { message: 'Hello, Vue 3!' } }, template: `<div>{{ message }}</div>` } // 在主应用中注册并使用该组件 new Vue({ el: '#app', components: { 'my-component': MyComponent }, template: `<my-component></my-component>` });
你可以通过 props 向子组件传递数据,并通过事件处理子组件的事件。
<!-- 父组件 --> <div id="app"> <child-component msg="Hello from parent"></child-component> </div> <!-- 子组件 --> <script> const ChildComponent = { props: ['msg'], template: `<p>{{ msg }}</p>` } </script>
子组件可以触发事件,父组件可以监听这些事件并处理它们。
<!-- 子组件 --> <script> const ChildComponent = { props: ['msg'], template: `<button v-on:click="notifyParent">Notify Parent</button>`, methods: { notifyParent() { this.$emit('my-event', 'Event triggered'); } } } </script> <!-- 父组件 --> <div id="app"> <child-component v-on:my-event="handleEvent" msg="Hello from parent"></child-component> </div> <script> new Vue({ el: '#app', components: { 'child-component': ChildComponent }, methods: { handleEvent(data) { console.log(data); // 输出: Event triggered } } }); </script>
Vue 3 的响应式系统基于 ES6 的 Proxy 对象,它能够监听到对象内部属性的变化,从而实现数据驱动的视图更新。以下是简单的示例:
const data = reactive({ count: 0 }); watch(() => data.count, (newVal, oldVal) => { console.log(`count changed from ${oldVal} to ${newVal}`); });
Vue 3 提供了 watch
和 computed
两种方式来处理依赖数据的变化。
const data = reactive({ count: 0, firstName: 'John', lastName: 'Doe' }); // 使用watch侦听指定的属性变化 watch(() => data.count, (newVal, oldVal) => { console.log(`count changed from ${oldVal} to ${newVal}`); }); // 使用computed属性简化复杂的依赖计算 const fullName = computed(() => `${data.firstName} ${data.lastName}`);
在大型应用中,通常需要进行全局状态管理。Vue 3 支持使用 Vuex 来管理全局状态。
import { createStore } from 'vuex'; const store = createStore({ state() { return { count: 0 }; }, mutations: { increment(state) { state.count++; } }, actions: { increment({ commit }) { commit('increment'); } } }); // 在组件中使用store const MyComponent = { setup() { const { count, increment } = useStore(); return { count, increment }; }, template: `<p>{{ count }}</p><button @click="increment">Increment</button>` }; // 定义useStore方法 import { computed } from 'vue'; const useStore = () => { const store = createStore({ state() { return { count: 0 }; }, mutations: { increment(state) { state.count++; } }, actions: { increment({ commit }) { commit('increment'); } } }); return { count: computed(() => store.state.count), increment: () => store.dispatch('increment') }; };
Vue Router 是 Vue.js 的官方路由管理器。以下是一个简单的路由配置示例:
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;
路由守卫可以用来控制访问路由的行为,例如在用户未登录时阻止访问某些页面。
router.beforeEach((to, from, next) => { if (to.matched.some(record => record.meta.requiresAuth)) { if (store.state.isAuthenticated) { next(); } else { next({ name: 'Login' }); } } else { next(); } });
Vuex 是 Vue.js 的状态管理模式。以下是一个简单的 Vuex 配置示例:
import { createStore } from 'vuex'; const store = createStore({ state: { count: 0 }, mutations: { increment(state) { state.count++; } }, actions: { increment({ commit }) { commit('increment'); } } }); // 在组件中使用store const MyComponent = { setup() { const { count, increment } = useStore(); return { count, increment }; }, template: `<p>{{ count }}</p><button @click="increment">Increment</button>` }; // 定义useStore方法 import { computed } from 'vue'; const useStore = () => { const store = createStore({ state: () => ({ count: 0 }), mutations: { increment(state) { state.count++; } }, actions: { increment({ commit }) { commit('increment'); } } }); return { count: computed(() => store.state.count), increment: () => store.dispatch('increment') }; };
待办事项应用通常包含以下功能:
首先,我们创建一个列表组件 TodoList.vue
,用于显示待办事项列表。
<template> <ul> <li v-for="todo in todos" :key="todo.id"> <span>{{ todo.text }}</span> <button @click="removeTodo(todo.id)">删除</button> </li> </ul> </template> <script> import { reactive, toRefs } from 'vue'; export default { props: ['todos'], setup(props) { const state = reactive({ todos: props.todos }); const removeTodo = (id) => { state.todos = state.todos.filter(todo => todo.id !== id); }; return { ...toRefs(state), removeTodo }; } } </script>
接下来,我们创建一个 TodoItem.vue
组件,用于添加新的待办事项。
<template> <div> <input v-model="newTodo" placeholder="输入待办事项" /> <button @click="addTodo">添加</button> </div> </template> <script> import { reactive, toRefs } from 'vue'; export default { setup() { const state = reactive({ newTodo: '', todos: [] }); const addTodo = () => { if (state.newTodo) { state.todos.push({ id: new Date().getTime(), text: state.newTodo }); state.newTodo = ''; } }; return { ...toRefs(state), addTodo }; } } </script>
为了保存和加载数据,我们可以使用浏览器的 localStorage
。
<template> <div id="app"> <todo-item @add-todo="addTodo"></todo-item> <todo-list :todos="todos"></todo-list> </div> </template> <script> import { ref, onMounted } from 'vue'; import { useStore } from 'vuex'; import TodoItem from './components/TodoItem.vue'; import TodoList from './components/TodoList.vue'; const todos = ref(JSON.parse(localStorage.getItem('todos')) || []); const addTodo = (todo) => { todos.value.push(todo); saveTodos(); }; const saveTodos = () => { localStorage.setItem('todos', JSON.stringify(todos.value)); }; onMounted(() => { watch(todos, saveTodos, { deep: true }); }); export default { components: { TodoItem, TodoList }, setup() { return { todos, addTodo }; } }; </script>
在开发环境中,我们使用 npm run serve
启动开发服务器,而在生产环境中,我们需要构建项目并部署到服务器。
# 开发环境 npm run serve # 生产环境 npm run build
构建成功后,会在 dist
目录下生成一个生产环境的静态文件,可以将其部署到任何静态文件服务器上。
构建项目后,你需要将构建输出的文件部署到服务器上。以下是简单的部署步骤:
构建项目:
npm run build
将构建输出的静态文件部署到服务器,例如使用 Nginx 或 Apache 服务器。
配置 Nginx:
server { listen 80; server_name example.com; location / { root /path/to/dist; try_files $uri /index.html; } }
<VirtualHost *:80> ServerName example.com DocumentRoot /path/to/dist <Directory /path/to/dist> Options -Indexes +FollowSymLinks AllowOverride None Require all granted </Directory> </VirtualHost>
在开发过程中,你可能会遇到各种问题,这里列出一些常见的问题及解决方法:
ref
和 reactive
正确地管理状态。reactive
或 ref
,以及数据是否正确地传递给了组件。