手记

Vue3项目实战:从入门到上手

概述

本文详细介绍了如何从零开始构建Vue3项目,涵盖准备工作、基础语法、组件化开发、状态管理与路由、实战项目案例等内容,帮助开发者快速上手Vue3项目实战。文中不仅讲解了项目的创建和基本功能实现,还提供了详细的代码示例和实战演练,确保开发者能够掌握Vue3的核心特性和最佳实践。

准备工作

在开始开发Vue3项目前,需要确保已安装Node.js和Vue CLI,并按照步骤创建Vue3项目。

安装Node.js和Vue CLI

  1. 安装Node.js

    首先,确保已安装Node.js。访问官方网站(https://nodejs.org/)下载最新版本的Node.js,安装完成后确保Node.js已正确安装

    # 检查Node.js版本
    node -v
    # 检查npm版本
    npm -v
  2. 安装Vue CLI

    Vue CLI是Vue.js的官方脚手架,用于快速搭建Vue应用。使用npm安装Vue CLI:

    npm install -g @vue/cli

    验证Vue CLI是否安装成功:

    vue --version

创建Vue3项目

使用Vue CLI创建Vue3项目。首先,创建一个新文件夹用于存放项目:

mkdir my-vue3-app
cd my-vue3-app

接着,使用Vue CLI创建项目。指定使用Vue 3的版本,使用以下命令:

vue create my-vue3-app

在创建过程中,Vue CLI会提示选择预设配置,选择Manually select features,然后选择Progressive Web AppRouterVuex等所需的功能。之后选择Vue 3作为预设版本。

项目结构简介

创建成功的Vue3项目结构如下:

my-vue3-app/
├── node_modules/
├── public/
│   ├── favicon.ico
│   ├── index.html
│   └── manifest.json
├── src/
│   ├── assets/
│   ├── components/
│   ├── App.vue
│   ├── main.js
│   ├── router/
│   │   └── index.js
│   └── store/
│       └── index.js
├── .gitignore
├── babel.config.js
├── package.json
├── README.md
└── vue.config.js
  • public/:存放静态资源,如index.html
  • src/:项目的主要代码文件。App.vue是应用的主要入口组件,main.js是应用的启动文件。
  • router/:存放路由配置文件index.js
  • store/:存放状态管理文件index.js

Vue3基础语法

模板语法

Vue使用模板语法将HTML与JavaScript绑定。模板语法由插值表达式({{ }})、指令(以v-开头的属性)、和事件绑定组成。

  1. 插值表达式

    插值表达式用于显示变量的值:

    <div id="app">
     <span>{{ message }}</span>
    </div>

    相应的JS代码:

    new Vue({
     el: '#app',
     data: {
       message: 'Hello Vue!'
     }
    });
  2. 指令

    指令是带有v-前缀的特殊属性。例如,v-bind用于动态绑定属性:

    <div id="app">
     <img v-bind:src="imageSrc" />
    </div>

    相应的JS代码:

    new Vue({
     el: '#app',
     data: {
       imageSrc: 'https://example.com/image.jpg'
     }
    });

计算属性与方法

计算属性是基于数据变量的派生值。适用于涉及复杂计算的数据。方法则用于操作数据或执行逻辑。

  1. 计算属性

    <div id="app">
     <p>{{ fullName }}</p>
    </div>

    相应的JS代码:

    new Vue({
     el: '#app',
     data: {
       firstName: 'John',
       lastName: 'Doe'
     },
     computed: {
       fullName: function() {
         return `${this.firstName} ${this.lastName}`;
       }
     }
    });
  2. 方法

    <div id="app">
     <button v-on:click="sayHello">Say Hello</button>
    </div>

    相应的JS代码:

    new Vue({
     el: '#app',
     methods: {
       sayHello: function() {
         alert('Hello!');
       }
     }
    });

指令和事件绑定

Vue提供多种内置指令来操作DOM元素。例如v-ifv-forv-on等。

  1. 条件渲染

    使用v-ifv-else指令来根据条件渲染元素:

    <div id="app">
     <p v-if="isLoggedIn">You are logged in</p>
     <p v-else>You are not logged in</p>
    </div>

    相应的JS代码:

    new Vue({
     el: '#app',
     data: {
       isLoggedIn: false
     }
    });
  2. 列表渲染

    使用v-for指令来遍历数组或对象:

    <div id="app">
     <ul>
       <li v-for="item in items">{{ item }}</li>
     </ul>
    </div>

    相应的JS代码:

    new Vue({
     el: '#app',
     data: {
       items: ['Item 1', 'Item 2', 'Item 3']
     }
    });
  3. 事件绑定

    使用v-on指令来绑定事件处理程序:

    <div id="app">
     <button v-on:click="increment">Increment</button>
     <p>{{ count }}</p>
    </div>

    相应的JS代码:

    new Vue({
     el: '#app',
     data: {
       count: 0
     },
     methods: {
       increment: function() {
         this.count += 1;
       }
     }
    });

组件化开发

创建和使用组件

  1. 创建组件

    首先,创建一个新组件文件,例如HelloWorld.vue

    <!-- HelloWorld.vue -->
    <template>
     <div class="hello">
       <h1>{{ message }}</h1>
     </div>
    </template>
    
    <script>
    export default {
     name: 'HelloWorld',
     props: {
       message: String
     }
    }
    </script>
    
    <style scoped>
    .hello {
     color: red;
    }
    </style>
  2. 在父组件中使用组件

    在父组件中引入并使用新创建的组件:

    <!-- App.vue -->
    <template>
     <div id="app">
       <HelloWorld message="Hello from App.vue" />
     </div>
    </template>
    
    <script>
    import HelloWorld from './components/HelloWorld.vue'
    
    export default {
     name: 'App',
     components: {
       HelloWorld
     }
    }
    </script>

属性传递与事件监听

  1. 属性传递

    App.vue中传递属性给HelloWorld组件:

    <!-- App.vue -->
    <template>
     <div id="app">
       <HelloWorld message="Hello from App.vue" />
     </div>
    </template>
    
    <script>
    import HelloWorld from './components/HelloWorld.vue'
    
    export default {
     name: 'App',
     components: {
       HelloWorld
     }
    }
    </script>

    HelloWorld.vue中接收并使用属性:

    <!-- HelloWorld.vue -->
    <template>
     <div class="hello">
       <h1>{{ message }}</h1>
     </div>
    </template>
    
    <script>
    export default {
     name: 'HelloWorld',
     props: {
       message: String
     }
    }
    </script>
  2. 事件监听

    HelloWorld.vue中定义一个自定义事件,并在父组件中监听该事件:

    <!-- HelloWorld.vue -->
    <template>
     <div class="hello">
       <h1>{{ message }}</h1>
       <button @click="sendEvent">Send Event</button>
     </div>
    </template>
    
    <script>
    export default {
     name: 'HelloWorld',
     props: {
       message: String
     },
     methods: {
       sendEvent() {
         this.$emit('custom-event', 'Data sent from child component');
       }
     }
    }
    </script>

    App.vue中定义事件监听器:

    <!-- App.vue -->
    <template>
     <div id="app">
       <HelloWorld message="Hello from App.vue" @custom-event="handleEvent" />
     </div>
    </template>
    
    <script>
    import HelloWorld from './components/HelloWorld.vue'
    
    export default {
     name: 'App',
     components: {
       HelloWorld
     },
     methods: {
       handleEvent(data) {
         console.log(data);
       }
     }
    }
    </script>

插槽与动态组件

  1. 插槽

    使用插槽来允许父组件向子组件插入内容:

    <!-- HelloWorld.vue -->
    <template>
     <div class="hello">
       <h1>{{ message }}</h1>
       <slot></slot>
     </div>
    </template>
    
    <script>
    export default {
     name: 'HelloWorld',
     props: {
       message: String
     }
    }
    </script>

    App.vue中使用插槽:

    <!-- App.vue -->
    <template>
     <div id="app">
       <HelloWorld message="Hello from App.vue">
         <p>This is some custom content</p>
       </HelloWorld>
     </div>
    </template>
    
    <script>
    import HelloWorld from './components/HelloWorld.vue'
    
    export default {
     name: 'App',
     components: {
       HelloWorld
     }
    }
    </script>
  2. 动态组件

    使用<component>标签和is属性来动态切换组件:

    <!-- App.vue -->
    <template>
     <div id="app">
       <button @click="componentName = 'HelloWorld'">Show HelloWorld</button>
       <button @click="componentName = 'AnotherComponent'">Show AnotherComponent</button>
       <component :is="componentName"></component>
     </div>
    </template>
    
    <script>
    import HelloWorld from './components/HelloWorld.vue';
    import AnotherComponent from './components/AnotherComponent.vue';
    
    export default {
     name: 'App',
     data() {
       return {
         componentName: 'HelloWorld'
       };
     },
     components: {
       HelloWorld,
       AnotherComponent
     }
    }
    </script>

状态管理与路由

使用Vuex进行状态管理

  1. 安装Vuex

    使用Vue CLI创建项目时,可以选择安装Vuex。如果没有安装,可以手动安装:

    npm install vuex --save
  2. 创建Vuex store

    创建src/store/index.js文件:

    import Vue from 'vue';
    import Vuex from 'vuex';
    
    Vue.use(Vuex);
    
    export default new Vuex.Store({
     state: {
       count: 0
     },
     mutations: {
       increment(state) {
         state.count++;
       }
     },
     actions: {
       increment({ commit }) {
         commit('increment');
       }
     }
    });
  3. 在组件中使用Vuex

    在组件中使用Vuex,首先需要引入mapActions

    import { mapActions } from 'vuex';
    
    export default {
     name: 'App',
     methods: {
       ...mapActions(['increment'])
     }
    };

    在模板中调用Vuex的方法:

    <template>
     <div id="app">
       <p>{{ $store.state.count }}</p>
       <button @click="increment()">Increment</button>
     </div>
    </template>

Vue Router的基本使用

  1. 安装Vue Router

    使用Vue CLI创建项目时,可以选择安装Vue Router。如果没有安装,可以手动安装:

    npm install vue-router --save
  2. 创建路由配置

    创建src/router/index.js文件:

    import Vue from 'vue';
    import Router from 'vue-router';
    import HelloWorld from '@/components/HelloWorld.vue';
    
    Vue.use(Router);
    
    export default new Router({
     routes: [
       {
         path: '/',
         name: 'HelloWorld',
         component: HelloWorld
       },
       {
         path: '/another',
         name: 'AnotherComponent',
         component: () => import('@/components/AnotherComponent.vue')
       }
     ]
    });
  3. 在主文件中使用路由

    src/main.js中引入并使用路由:

    import Vue from 'vue';
    import App from './App.vue';
    import router from './router';
    
    new Vue({
     el: '#app',
     router,
     render: h => h(App)
    });
  4. 导航到路由

    在模板中使用<router-link><router-view>来导航到不同路由:

    <template>
     <div id="app">
       <router-link to="/">Home</router-link>
       <router-link to="/another">Another</router-link>
       <router-view></router-view>
     </div>
    </template>

路由的动态参数与守卫

  1. 动态参数

    在路由中使用动态参数:

    export default new Router({
     routes: [
       {
         path: '/user/:id',
         name: 'User',
         component: () => import('@/components/User.vue')
       }
     ]
    });

    在组件中访问动态参数:

    <template>
     <div id="user">
       <p>User ID: {{ $route.params.id }}</p>
     </div>
    </template>
    
    <script>
    export default {
     name: 'User'
    }
    </script>
  2. 路由守卫

    使用路由守卫来控制导航行为:

    import Vue from 'vue';
    import Router from 'vue-router';
    import HelloWorld from '@/components/HelloWorld.vue';
    
    Vue.use(Router);
    
    const router = new Router({
     routes: [
       {
         path: '/',
         name: 'HelloWorld',
         component: HelloWorld
       }
     ]
    });
    
    router.beforeEach((to, from, next) => {
     console.log('Navigating from', from.path, 'to', to.path);
     next();
    });
    
    export default router;

常见问题解决

常见错误与调试技巧

  1. 错误常见原因

    • 模板错误:模板中使用了不存在的变量或指令。
    • 组件未定义:在父组件中使用了未定义的子组件。
    • 状态管理问题:Vuex store中状态未正确更新。
  2. 调试技巧

    • Vue Devtools:安装Vue Devtools浏览器插件,帮助检查Vue应用的状态。
    • 控制台日志:在组件或方法中打印日志,检查变量的值。
    • 断点调试:使用浏览器开发者工具中的断点功能,调试Vue应用中的代码。

性能优化方法

  1. 懒加载

    使用Vue Router的懒加载功能,按需加载组件:

    import Vue from 'vue';
    import Router from 'vue-router';
    import HelloWorld from '@/components/HelloWorld.vue';
    
    Vue.use(Router);
    
    export default new Router({
     routes: [
       {
         path: '/',
         name: 'HelloWorld',
         component: HelloWorld
       },
       {
         path: '/lazy',
         name: 'LazyComponent',
         component: () => import('@/components/LazyComponent.vue')
       }
     ]
    });
  2. 状态管理优化

    使用Vuex的actionsmutations来优化状态管理:

    import Vue from 'vue';
    import Vuex from 'vuex';
    
    Vue.use(Vuex);
    
    export default new Vuex.Store({
     state: {
       count: 0
     },
     mutations: {
       increment(state) {
         state.count++;
       }
     },
     actions: {
       increment({ commit }) {
         commit('increment');
       }
     }
    });

测试Vue3应用

  1. 单元测试

    使用vue-test-utilsjest进行单元测试:

    npm install vue-test-utils jest --save-dev

    创建测试文件src/components/HelloWorld.spec.js

    import { shallowMount } from '@vue/test-utils';
    import HelloWorld from '@/components/HelloWorld.vue';
    
    describe('HelloWorld.vue', () => {
     it('renders props.message when passed', () => {
       const wrapper = shallowMount(HelloWorld, {
         propsData: { message: 'Hello' }
       });
       expect(wrapper.text()).toBe('Hello');
     });
    });
  2. 集成测试

    使用vue-test-utilsjest进行集成测试:

    import { shallowMount } from '@vue/test-utils';
    import App from '@/App.vue';
    
    describe('App.vue', () => {
     it('renders HelloWorld component', () => {
       const wrapper = shallowMount(App);
       expect(wrapper.findComponent({ name: 'HelloWorld' })).toBeTruthy();
     });
    });

实战项目案例

小项目实战演练

创建一个简单的CRUD应用,包括增删改查功能。

  1. 项目需求

    • 用户可以添加、编辑、删除和查看用户列表。
  2. 项目结构

    创建项目文件夹my-crud-app,安装Vue CLI创建项目:

    vue create my-crud-app
  3. 定义数据模型

    src/store/index.js中定义用户数据模型:

    import Vue from 'vue';
    import Vuex from 'vuex';
    
    Vue.use(Vuex);
    
    export default new Vuex.Store({
     state: {
       users: []
     },
     mutations: {
       add(state, user) {
         state.users.push(user);
       },
       remove(state, id) {
         state.users = state.users.filter(user => user.id !== id);
       },
       update(state, updatedUser) {
         const index = state.users.findIndex(user => user.id === updatedUser.id);
         if (index !== -1) {
           state.users[index] = updatedUser;
         }
       }
     },
     actions: {
       add({ commit }, user) {
         commit('add', user);
       },
       remove({ commit }, id) {
         commit('remove', id);
       },
       update({ commit }, updatedUser) {
         commit('update', updatedUser);
       }
     }
    });
  4. 创建用户组件

    创建src/components/UserForm.vue用于添加和编辑用户:

    <template>
     <form @submit.prevent="handleSubmit">
       <label>
         名称:
         <input type="text" v-model="name" />
       </label>
       <label>
         年龄:
         <input type="number" v-model.number="age" />
       </label>
       <button type="submit">{{ isEditing ? '更新' : '添加' }}</button>
     </form>
    </template>
    
    <script>
    export default {
     props: {
       name: String,
       age: Number,
       id: Number,
       isEditing: Boolean
     },
     methods: {
       handleSubmit() {
         if (this.isEditing) {
           this.$store.dispatch('update', { id: this.id, name: this.name, age: this.age });
         } else {
           this.$store.dispatch('add', { name: this.name, age: this.age });
         }
       }
     }
    }
    </script>

    创建src/components/UserList.vue用于显示用户列表:

    <template>
     <div>
       <UserForm v-if="isEditing" :name="editingUser.name" :age="editingUser.age" :id="editingUser.id" :isEditing="true" />
       <ul>
         <li v-for="user in users" :key="user.id">
           {{ user.name }} - {{ user.age }}
           <button @click="editUser(user)">编辑</button>
           <button @click="removeUser(user.id)">删除</button>
         </li>
       </ul>
       <UserForm v-if="!isEditing" />
     </div>
    </template>
    
    <script>
    import UserForm from './UserForm.vue';
    
    export default {
     components: {
       UserForm
     },
     computed: {
       users() {
         return this.$store.state.users;
       }
     },
     methods: {
       editUser(user) {
         this.$store.commit('SET_EDITING_USER', user);
         this.isEditing = true;
       },
       removeUser(id) {
         this.$store.dispatch('remove', id);
       }
     },
     data() {
       return {
         isEditing: false,
         editingUser: {}
       };
     }
    }
    </script>
  5. 在主应用中使用组件

    src/App.vue中引入并使用用户组件:

    <template>
     <div id="app">
       <UserList />
     </div>
    </template>
    
    <script>
    import UserList from './components/UserList.vue';
    
    export default {
     name: 'App',
     components: {
       UserList
     }
    }
    </script>

项目打包与部署

  1. 打包项目

    使用npm命令打包项目:

    npm run build

    打包后的文件会生成在dist/目录中。

  2. 部署项目

    将打包后的文件dist/目录中的文件上传到服务器,或使用CDN等服务发布应用。

代码审查与维护建议

  1. 代码审查

    • 组件化:确保所有功能封装成独立的组件。
    • 状态管理:确保状态管理逻辑清晰,易于维护。
    • 测试覆盖率:确保有足够的单元测试和集成测试覆盖应用。
  2. 维护建议

    • 文档编写:编写详细的文档,方便团队成员快速上手。
    • 版本控制:使用Git进行版本控制,确保代码版本的可追踪性。
    • 持续集成:使用CI/CD工具,确保代码质量。

通过以上步骤,可以创建一个从零开始的Vue3项目,并掌握Vue3的核心功能和项目开发的最佳实践。

0人推荐
随时随地看视频
慕课网APP