为了账号安全,请及时绑定邮箱和手机立即绑定

Vue3项目实战:新手入门到上手开发

概述

本文详细介绍了Vue3项目实战的全过程,从环境搭建到组件化开发,帮助新手快速入门。文章通过具体实例如待办事项列表和图书管理应用,展示了Vue3的实际应用,并涵盖了路由配置、状态管理以及项目部署与调试技巧,为开发者提供全面的实战指导。

Vue3项目实战:新手入门到上手开发
Vue3基础概念与环境搭建

Vue3简介

Vue3是Vue框架的最新版本,它在Vue2的基础上进行了许多改进,包括改进的响应式系统、更短的渲染时间、更好的TypeScript支持以及更灵活的组件API等。这些改进使得Vue3在开发大型应用时更加高效和灵活。

安装Node.js和Vue CLI

  1. 安装Node.js

    首先,需要安装Node.js,可以从官网下载最新版本的Node.js:https://nodejs.org/en/download/

    下载完成后,运行安装程序,按照提示完成安装。安装完成后可以在命令行中输入以下命令检查Node.js是否安装成功:

    node -v
    npm -v
  2. 安装Vue CLI

    Vue CLI是一个命令行工具,可以方便地创建和管理Vue项目。安装Vue CLI需要使用npm,命令如下:

    npm install -g @vue/cli

    安装完成后,可以使用以下命令来验证Vue CLI是否安装成功:

    vue --version

创建第一个Vue3项目

使用Vue CLI创建一个新的Vue项目,执行以下命令:

vue create my-vue3-app

在创建过程中,可以选择预设的配置或选择手动选择特性。由于我们使用Vue3,需要在命令行中明确指定使用Vue3版本,可以通过以下命令来创建使用Vue3的新项目:

vue create -d my-vue3-app

选择Vue版本时,确保选择Vue 3.x。

创建完成后,项目的目录结构如下:

my-vue3-app/
├── node_modules/
├── public/
├── src/
├── .gitignore
├── babel.config.js
├── package.json
├── README.md
└── vue.config.js
  • node_modules/:存放项目依赖包。
  • public/:存放静态文件,如index.html。
  • src/:存放项目源代码。
  • .gitignore:指定文件或目录是否受Git版本控制系统管理。
  • babel.config.js:配置Babel编译器。
  • package.json:项目配置文件,包含依赖项列表、脚本命令等。
  • README.md:项目文档。
  • vue.config.js:Vue CLI配置文件,用于自定义构建设置。

Vue3组件化开发

组件的基本使用

Vue3中,组件是构建应用的基础。每个组件都有自己的模板、样式和逻辑。创建一个简单的Vue组件步骤如下:

  1. 创建组件文件

    src/components目录下创建一个名为HelloWorld.vue的新文件:

    <template>
     <div class="hello">
       <h1>Hello, World!</h1>
     </div>
    </template>
    
    <script>
    export default {
     name: 'HelloWorld'
    }
    </script>
    
    <style scoped>
    .hello {
     color: #42b983;
    }
    </style>
  2. 注册并使用组件

    在需要使用该组件的页面或父组件中进行注册和使用:

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

Props和Events传递数据

  1. Props传递数据

    在父组件中将数据通过Props传递给子组件:

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

    在子组件中定义Props并使用它们:

    <template>
     <div class="hello">
       <h1>{{ msg }}</h1>
     </div>
    </template>
    
    <script>
    export default {
     name: 'HelloWorld',
     props: {
       msg: String
     }
    }
    </script>
  2. Events传递数据

    子组件通过事件将数据传递给父组件:

    <template>
     <div class="hello">
       <button @click="sendDataToParent">Send Data</button>
     </div>
    </template>
    
    <script>
    export default {
     name: 'HelloWorld',
     props: {
       msg: String
     },
     methods: {
       sendDataToParent() {
         this.$emit('dataFromChild', 'Data from child component');
       }
     }
    }
    </script>

    在父组件中监听子组件的事件:

    <template>
     <div id="app">
       <HelloWorld msg="Hello from Parent" @dataFromChild="handleDataFromChild" />
     </div>
    </template>
    
    <script>
    import HelloWorld from './components/HelloWorld.vue'
    
    export default {
     name: 'App',
     components: {
       HelloWorld
     },
     methods: {
       handleDataFromChild(data) {
         alert(data);
       }
     }
    }
    </script>

插槽(Slots)的使用

插槽允许父组件向子组件中插入内容,从而实现组件的嵌套和复用。

  1. 定义插槽

    在子组件中定义插槽:

    <template>
     <div class="hello">
       <slot>Default slot content</slot>
     </div>
    </template>
    
    <script>
    export default {
     name: 'HelloWorld'
    }
    </script>
  2. 使用插槽

    在父组件中使用插槽向子组件插入内容:

    <template>
     <div id="app">
       <HelloWorld>
         <template v-slot>
           <h2>Custom slot content</h2>
         </template>
       </HelloWorld>
     </div>
    </template>
Vue3的响应式原理与数据绑定

响应式数据绑定

Vue3通过Proxy对象实现了更为强大的响应式系统。Proxy对象可以监测对象属性的添加、修改和删除操作,以及属性的读取。响应式系统的核心是将数据对象包装在一个Proxy对象中,当数据更改时,可以自动触发视图的更新。

  1. 基本使用

    <template>
     <div>
       <p>{{ message }}</p>
       <button @click="updateMessage">Change Message</button>
     </div>
    </template>
    
    <script>
    export default {
     data() {
       return {
         message: 'Hello Vue 3'
       };
     },
     methods: {
       updateMessage() {
         this.message = 'Hello, Vue 3!';
       }
     }
    }
    </script>

计算属性和侦听器

  1. 计算属性

    计算属性是基于组件的响应式数据派生的。它们是依赖于其他数据的复杂计算。计算属性会记住它们的依赖关系,并在依赖发生变化时进行更新。

    <template>
     <div>
       <p>{{ fullName }}</p>
       <input v-model="firstName" placeholder="First Name" />
       <input v-model="lastName" placeholder="Last Name" />
     </div>
    </template>
    
    <script>
    export default {
     data() {
       return {
         firstName: '',
         lastName: ''
       };
     },
     computed: {
       fullName() {
         return `${this.firstName} ${this.lastName}`;
       }
     }
    }
    </script>
  2. 侦听器

    当需要执行副作用操作或需要更复杂的响应式逻辑时,可以使用侦听器。侦听器可以在数据变化时执行异步或时间开销较大的操作。

    <template>
     <div>
       <p>{{ message }}</p>
       <input v-model="message" placeholder="Type here" />
     </div>
    </template>
    
    <script>
    export default {
     data() {
       return {
         message: ''
       };
     },
     watch: {
       message(newVal, oldVal) {
         console.log('Old value:', oldVal);
         console.log('New value:', newVal);
       }
     }
    }
    </script>

生命周期钩子

Vue实例有一个完整的生命周期,从创建到销毁每个过程都有对应的生命周期钩子。这些钩子可以在特定的时机执行自定义逻辑。

  1. 生命周期钩子列表

    • beforeCreate
    • created
    • beforeMount
    • mounted
    • beforeUpdate
    • updated
    • beforeUnmount
    • unmounted
    • errorCaptured
  2. 使用示例

    <template>
     <div>
       <p>{{ message }}</p>
     </div>
    </template>
    
    <script>
    export default {
     data() {
       return {
         message: 'Hello Vue 3'
       };
     },
     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>
Vue3路由与状态管理

路由的基本使用

Vue Router是Vue.js官方的路由库,它基于Vue的组件系统实现了路由功能。使用Vue Router可以让单页面应用(SPA)根据URL的变化来切换视图组件。

  1. 安装Vue Router

    npm install vue-router@next --save
  2. 配置基础路由

    在项目中创建一个路由配置文件src/router/index.js

    import { createRouter, createWebHistory } from 'vue-router';
    import Home from '../views/Home.vue';
    import About from '../views/About.vue';
    
    const routes = [
     {
       path: '/',
       name: 'Home',
       component: Home
     },
     {
       path: '/about',
       name: 'About',
       component: About
     }
    ];
    
    const router = createRouter({
     history: createWebHistory(),
     routes
    });
    
    export default router;
  3. 注册和使用路由

    在主应用文件src/main.js中引入并使用路由:

    import { createApp } from 'vue';
    import App from './App.vue';
    import router from './router';
    
    createApp(App).use(router).mount('#app');

配置多级路由

多级路由可以通过嵌套路由实现。在子组件中定义路由,然后在父组件的路由配置中引用它们。

  1. 创建子组件

    src/views/Home.vue中:

    <template>
     <div>
       <h1>Home</h1>
       <router-link to="/home/child1">Child 1</router-link>
       <router-link to="/home/child2">Child 2</router-link>
       <router-view />
     </div>
    </template>
    
    <script>
    import Child1 from './Child1.vue';
    import Child2 from './Child2.vue';
    
    export default {
     components: {
       Child1,
       Child2
     }
    }
    </script>
  2. 定义嵌套路由

    在路由配置文件中添加嵌套路由:

    import { createRouter, createWebHistory } from 'vue-router';
    import Home from '../views/Home.vue';
    import About from '../views/About.vue';
    import Child1 from '../views/Child1.vue';
    import Child2 from '../views/Child2.vue';
    
    const routes = [
     {
       path: '/',
       name: 'Home',
       component: Home,
       children: [
         {
           path: 'child1',
           name: 'Child1',
           component: Child1
         },
         {
           path: 'child2',
           name: 'Child2',
           component: Child2
         }
       ]
     },
     {
       path: '/about',
       name: 'About',
       component: About
     }
    ];
    
    const router = createRouter({
     history: createWebHistory(),
     routes
    });
    
    export default router;

Vuex状态管理库简介与使用

Vuex是Vue官方的状态管理模式,它将应用程序的状态集中管理,可以方便地实现状态的统一管理和操作。

  1. 安装Vuex

    npm install vuex@next --save
  2. 配置Vuex

    在项目中创建一个Vuex store文件src/store/index.js

    import { createStore } from 'vuex';
    
    export default createStore({
     state: {
       count: 0
     },
     mutations: {
       increment(state) {
         state.count++;
       },
       decrement(state) {
         state.count--;
       }
     },
     actions: {
       increment({ commit }) {
         commit('increment');
       },
       decrement({ commit }) {
         commit('decrement');
       }
     }
    });
  3. 使用store

    在主应用文件src/main.js中引入并使用store:

    import { createApp } from 'vue';
    import App from './App.vue';
    import router from './router';
    import store from './store';
    
    createApp(App).use(router).use(store).mount('#app');

    在组件中使用store:

    <template>
     <div>
       <p>{{ count }}</p>
       <button @click="increment">Increment</button>
       <button @click="decrement">Decrement</button>
     </div>
    </template>
    
    <script>
    import { mapState, mapActions } from 'vuex';
    
    export default {
     computed: {
       ...mapState(['count'])
     },
     methods: {
       ...mapActions(['increment', 'decrement'])
     }
    }
    </script>
Vue3项目实战案例

实战案例一:创建一个简单的待办事项列表应用

  1. 项目结构

    todo-app/
    ├── node_modules/
    ├── public/
    ├── src/
    │   ├── App.vue
    │   ├── main.js
    │   ├── router/
    │   │   └── index.js
    │   ├── store/
    │   │   └── index.js
    │   ├── components/
    │   │   ├── TodoItem.vue
    │   │   └── TodoList.vue
    │   ├── views/
    │   │   └── Home.vue
    ├── .gitignore
    ├── babel.config.js
    ├── package.json
    ├── README.md
    └── vue.config.js
  2. 组件实现

    • TodoItem.vue

      <template>
      <li>
       <input type="checkbox" v-model="checked" />
       <span :class="{ completed: checked }">{{ todo.text }}</span>
       <button @click="remove">Remove</button>
      </li>
      </template>
      
      <script>
      export default {
      props: ['todo'],
      data() {
       return {
         checked: this.todo.completed
       };
      },
      methods: {
       remove() {
         this.$emit('remove', this.todo.id);
       }
      },
      watch: {
       checked(newVal) {
         this.$emit('update', this.todo.id, newVal);
       }
      }
      }
      </script>
      
      <style scoped>
      li {
      list-style: none;
      }
      span.completed {
      text-decoration: line-through;
      }
      </style>
    • TodoList.vue

      <template>
      <div>
       <form @submit.prevent="addTodo">
         <input v-model="newTodo" placeholder="New todo" />
         <button type="submit">Add</button>
       </form>
       <ul>
         <TodoItem
           v-for="todo in todos"
           :key="todo.id"
           :todo="todo"
           @update="updateTodo"
           @remove="removeTodo"
         />
       </ul>
      </div>
      </template>
      
      <script>
      import TodoItem from './TodoItem.vue';
      
      export default {
      components: {
       TodoItem
      },
      data() {
       return {
         newTodo: '',
         todos: [
           { id: 1, text: 'Learn Vue 3', completed: false },
           { id: 2, text: 'Learn Vuex', completed: false }
         ]
       };
      },
      methods: {
       addTodo() {
         if (this.newTodo.trim() === '') return;
         const newId = this.todos.length ? Math.max(...this.todos.map(t => t.id)) + 1 : 1;
         this.todos.push({ id: newId, text: this.newTodo, completed: false });
         this.newTodo = '';
       },
       updateTodo(id, completed) {
         this.todos = this.todos.map(todo => {
           if (todo.id === id) {
             return { ...todo, completed };
           }
           return todo;
         });
       },
       removeTodo(id) {
         this.todos = this.todos.filter(todo => todo.id !== id);
       }
      }
      }
      </script>
    • Home.vue

      <template>
      <TodoList />
      </template>
      
      <script>
      import TodoList from '../components/TodoList.vue';
      
      export default {
      components: {
       TodoList
      }
      }
      </script>
  3. 路由配置

    import { createRouter, createWebHistory } from 'vue-router';
    import Home from '../views/Home.vue';
    
    const routes = [
     {
       path: '/',
       name: 'Home',
       component: Home
     }
    ];
    
    const router = createRouter({
     history: createWebHistory(),
     routes
    });
    
    export default router;
    import { createApp } from 'vue';
    import App from './App.vue';
    import router from './router';
    
    createApp(App).use(router).mount('#app');

实战案例二:创建一个简单的图书管理应用

  1. 项目结构

    book-manager/
    ├── node_modules/
    ├── public/
    ├── src/
    │   ├── App.vue
    │   ├── main.js
    │   ├── router/
    │   │   └── index.js
    │   ├── store/
    │   │   └── index.js
    │   ├── components/
    │   │   ├── BookItem.vue
    │   │   └── BookList.vue
    │   ├── views/
    │   │   └── Home.vue
    ├── .gitignore
    ├── babel.config.js
    ├── package.json
    ├── README.md
    └── vue.config.js
  2. 组件实现

    • BookItem.vue

      <template>
      <li>
       <h3>{{ book.title }}</h3>
       <p>Author: {{ book.author }}</p>
       <p>Pages: {{ book.pages }}</p>
       <button @click="remove">Remove</button>
      </li>
      </template>
      
      <script>
      export default {
      props: ['book'],
      methods: {
       remove() {
         this.$emit('remove', this.book.id);
       }
      }
      }
      </script>
      
      <style scoped>
      li {
      list-style: none;
      margin-bottom: 10px;
      }
      </style>
    • BookList.vue

      <template>
      <div>
       <form @submit.prevent="addBook">
         <input v-model="newBook.title" placeholder="Title" />
         <input v-model="newBook.author" placeholder="Author" />
         <input v-model.number="newBook.pages" placeholder="Pages" type="number" />
         <button type="submit">Add</button>
       </form>
       <ul>
         <BookItem
           v-for="book in books"
           :key="book.id"
           :book="book"
           @remove="removeBook"
         />
       </ul>
      </div>
      </template>
      
      <script>
      import BookItem from './BookItem.vue';
      
      export default {
      components: {
       BookItem
      },
      data() {
       return {
         newBook: {
           title: '',
           author: '',
           pages: 0
         },
         books: [
           { id: 1, title: 'Vue 3 Guide', author: 'Vue Team', pages: 250 },
           { id: 2, title: 'Vuex Documentation', author: 'Vue Team', pages: 150 }
         ]
       };
      },
      methods: {
       addBook() {
         if (!this.newBook.title || !this.newBook.author || !this.newBook.pages) return;
         const newId = this.books.length ? Math.max(...this.books.map(b => b.id)) + 1 : 1;
         this.books.push({ id: newId, ...this.newBook });
         this.newBook = { title: '', author: '', pages: 0 };
       },
       removeBook(id) {
         this.books = this.books.filter(book => book.id !== id);
       }
      }
      }
      </script>
    • Home.vue

      <template>
      <BookList />
      </template>
      
      <script>
      import BookList from '../components/BookList.vue';
      
      export default {
      components: {
       BookList
      }
      }
      </script>
  3. 路由配置

    import { createRouter, createWebHistory } from 'vue-router';
    import Home from '../views/Home.vue';
    
    const routes = [
     {
       path: '/',
       name: 'Home',
       component: Home
     }
    ];
    
    const router = createRouter({
     history: createWebHistory(),
     routes
    });
    
    export default router;
    import { createApp } from 'vue';
    import App from './App.vue';
    import router from './router';
    
    createApp(App).use(router).mount('#app');
项目部署与调试技巧

项目构建与部署

在开发完成之后,可以使用Vue CLI提供的构建命令进行项目构建。构建后的项目可以部署到任何静态文件服务器上,例如GitHub Pages、Netlify或Vercel等。

  1. 构建项目

    在项目根目录下执行以下命令进行构建:

    npm run build

    构建完成后,会在dist/目录下生成构建后的文件,可以直接部署到静态文件服务器。

  2. 部署到GitHub Pages

    如果要将项目部署到GitHub Pages,可以按照以下步骤操作:

    • 创建一个新的GitHub仓库,将项目代码推送到仓库。
    • 进入仓库的Settings页面,找到GitHub Pages部分,选择从gh-pages分支或master分支发布站点。
    • 仓库会在几分钟内发布站点,URL形式为https://<username>.github.io/<repository>

常见问题及调试技巧

  1. 常见问题

    • Vue Router未生效:确保在主应用文件中正确引入并使用Vue Router。
    • 组件未正确加载:检查组件的路径是否正确,组件是否被正确注册和使用。
    • 样式未生效:确保样式文件被正确引入,检查样式是否有优先级问题。
  2. 调试技巧

    • Vue Devtools:使用Vue Devtools插件可以帮助调试Vue应用,它提供了组件层级、状态管理、路由调试等功能。
    • Console日志:在开发过程中可以使用console.log打印相关信息,便于定位问题。
    • 断点调试:在Chrome开发者工具中设置断点,可以逐行调试代码,查看变量值的变化。
    • Vue CLI Service:Vue CLI提供了vue-cli-service命令,在运行过程中可以使用--inspect选项来开启调试模式,便于调试。

通过以上内容,您可以从基础到实战全面掌握Vue3的开发技术,为今后的项目开发打下坚实的基础。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
JAVA开发工程师
手记
粉丝
205
获赞与收藏
1008

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消