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

Vue3入门教程:从零开始学习Vue3框架

标签:
Vue.js
概述

Vue3是Vue框架的最新版本,带来了多项改进和优化,包括性能提升、Tree-shaking优化和Composition API等特性。本文详细介绍了Vue3的主要特点、安装配置过程以及基础语法,帮助开发者更好地理解和使用Vue3

Vue3简介

Vue3的主要特点

Vue3是Vue框架的最新版本,它在Vue2的基础上进行了多项改进和优化。以下是Vue3的主要特点:

  1. 性能提升Vue3通过新的响应式系统Ref实现了更快的渲染速度和更好的性能。Ref系统基于Proxy实现了更高效的依赖追踪,从而在开发大型应用时能够提供更出色的表现。
  2. Tree-shaking优化Vue3的代码结构更便于进行Tree-shaking。例如,在配置Webpack时可以开启Tree-shaking,从而在打包时更有效地去除未使用的代码,减小最终的文件大小。在构建配置中,可以设置:
    optimization: {
     usedExports: true,
     provideModuleInfo: true
    },
  3. Composition APIVue3引入了Composition API,提供了一种更灵活的方式组织逻辑代码。通过函数和对象的组合,开发者可以更轻松地管理组件的状态和逻辑。例如,以下是一个使用Composition API定义组件的例子:

    <template>
     <div>
       <p>{{ message }}</p>
     </div>
    </template>
    
    <script>
    import { ref } from 'vue';
    
    export default {
     setup() {
       const message = ref("Hello, Composition API!");
       return { message };
     }
    };
    </script>
  4. TypeScript支持增强Vue3对TypeScript的支持更加友好,提供了更好的类型推断和类型检查功能。这使得开发者能够更方便地使用TypeScript开发Vue应用。
  5. Teleport和FragmentsVue3引入了Teleport和Fragments两个新特性,允许开发者更灵活地处理DOM节点之间的插入关系。例如,Teleport可以将DOM节点插入到父组件之外的任何位置:
    <teleport to="body">
     <div class="notification">
       This is a notification
     </div>
    </teleport>
  6. 更好的错误处理Vue3改进了错误处理机制,提供了更详细的错误信息,帮助开发者更快地定位和修复问题。

Vue3与Vue2的区别

Vue3与Vue2的主要区别体现在以下几个方面:

  1. 响应式系统Vue3的响应式系统从基于Object.defineProperty的实现变更为基于Proxy的实现,这使得Vue3在处理复杂数据结构时更加高效。例如,Vue2中响应式系统的代码:
    Vue.set(vm.someObject, 'count', 1);

    Vue3中则使用ref

    import { ref } from 'vue';
    const count = ref(0);
    count.value++;
  2. Composition API:Vue2主要依赖Options API,而Vue3引入了Composition API,提供了更灵活的逻辑组合方式。例如,Options API:

    export default {
     data() {
       return {
         message: 'Hello Vue2!'
       };
     },
     methods: {
       greet() {
         console.log(this.message);
       }
     }
    };

    Composition API:

    import { ref } from 'vue';
    
    export default {
     setup() {
       const message = ref('Hello Vue3!');
       const greet = () => {
         console.log(message.value);
       };
       return { message, greet };
     }
    };
  3. Teleport和Fragments:Vue2没有Teleport和Fragments这两个特性,这意味着Vue2在处理DOM节点插入时不如Vue3灵活。
  4. Tree-shaking优化:Vue2的代码结构不如Vue3适合Tree-shaking,导致在打包时不能很好地去除未使用的代码。

Vue3的安装与配置

安装Vue3可以通过npm或yarn来完成。以下是安装和配置的基本步骤:

  1. 安装Node.js:确保你的系统已经安装了Node.js。可以从官网下载并安装最新版本。
  2. 安装Vue CLI:使用Vue CLI可以快速搭建Vue项目。可以通过以下命令安装Vue CLI:
    npm install -g @vue/cli
  3. 创建Vue项目:使用Vue CLI创建一个新的Vue项目:
    vue create my-vue3-project

    在创建过程中,可以选择使用Vue3,具体步骤如下:

    • 选择预设(Presets),选择默认的Vue3预设。
    • 选择特性(Features),根据需要选择特性,例如router、vuex等。
  4. 项目配置:进入项目目录并运行开发服务器:
    cd my-vue3-project
    npm run serve

    这将启动开发服务器,访问本地的http://localhost:8080即可看到Vue3项目。

基础语法

模板语法

Vue模板语法是基于HTML的,并通过一些特殊语法来描述如何将应用的内部数据绑定到DOM上。在Vue3中,模板语法仍然保持简洁和直观。以下是一些基础模板语法的示例:

  1. 插值:插值是最简单的模板语法形式,通过{{ }}来显示数据。
    <div>
     {{ message }}
    </div>
    export default {
     data() {
       return {
         message: 'Hello Vue3!'
       };
     }
    }
  2. v-ifv-if指令用于条件性地渲染元素。如果条件为true,则渲染元素;如果条件为false,则不渲染元素。
    <div v-if="seen">
     <p>The condition is true.</p>
    </div>
    export default {
     data() {
       return {
         seen: true
       };
     }
    }
  3. v-forv-for指令用于循环渲染列表。
    <ul>
     <li v-for="item in items" :key="item.id">{{ item.name }}</li>
    </ul>
    export default {
     data() {
       return {
         items: [
           { id: 1, name: 'Item 1' },
           { id: 2, name: 'Item 2' },
           { id: 3, name: 'Item 3' }
         ]
       };
     }
    }

数据绑定

数据绑定是Vue的核心功能之一,它允许你通过模板语法直接将应用内部的数据绑定到DOM元素上。Vue3提供了多种数据绑定的方式:

  1. v-model:用于双向数据绑定。当输入框的值发生变化时,相应的数据也会发生变化,并且反之亦然。
    <input v-model="message" />
    export default {
     data() {
       return {
         message: ''
       };
     }
    }
  2. v-bind:用于动态绑定属性。可以绑定HTML元素的属性,如classstyle等。
    <div v-bind:class="{ active: isActive }">
     This element is active
    </div>
    export default {
     data() {
       return {
         isActive: true
       };
     }
    }
  3. v-on:用于监听DOM事件。可以传递事件处理函数,也可以直接传递事件处理函数。
    <button v-on:click="increment">
     Click me
    </button>
    export default {
     data() {
       return {
         count: 0
       };
     },
     methods: {
       increment() {
         this.count++;
       }
     }
    }

计算属性和方法

计算属性和方法是Vue中用于处理数据的两种方式。计算属性是基于数据依赖进行缓存的,而方法则是在每次渲染时重新执行。

  1. 计算属性:计算属性是一个基于数据依赖进行缓存的属性。当依赖的数据发生变化时,计算属性会重新计算新的值。
    <div>{{ fullName }}</div>
    export default {
     data() {
       return {
         firstName: 'John',
         lastName: 'Doe'
       };
     },
     computed: {
       fullName() {
         return this.firstName + ' ' + this.lastName;
       }
     }
    }
  2. 方法:方法是在每次渲染时执行的函数。当依赖的数据发生变化时,方法会重新执行。
    <div>{{ fullName() }}</div>
    export default {
     data() {
       return {
         firstName: 'John',
         lastName: 'Doe'
       };
     },
     methods: {
       fullName() {
         return this.firstName + ' ' + this.lastName;
       }
     }
    }

组件化开发

单文件组件

单文件组件是Vue中一种常用的方式,它将组件的模板、脚本和样式封装在一个独立的.vue文件中。这样可以提高代码的复用性和可维护性。

  1. 创建单文件组件

    <template>
     <div>
       <p>{{ message }}</p>
     </div>
    </template>
    
    <script>
    export default {
     data() {
       return {
         message: 'Hello from a single-file component!'
       };
     }
    }
    </script>
    
    <style scoped>
    div {
     color: blue;
    }
    </style>
  2. 注册和使用组件
    在父组件中注册并使用这个单文件组件:

    <template>
     <div>
       <app-greeting></app-greeting>
     </div>
    </template>
    
    <script>
    import AppGreeting from './components/AppGreeting.vue';
    
    export default {
     components: {
       AppGreeting
     }
    }
    </script>

插槽与具名插槽

插槽是Vue中用于内容分发的一种机制。通过插槽,可以在组件中定义插槽位置,并在使用组件时填充这些位置。

  1. 基本插槽
    在子组件中定义插槽:

    <template>
     <div>
       <slot>Default slot content</slot>
     </div>
    </template>
    
    <script>
    export default {
     data() {
       return {
         message: 'This is a slot content.'
       };
     }
    }
    </script>

    在父组件中使用插槽:

    <template>
     <child-component>
       <p>{{ message }}</p>
     </child-component>
    </template>
    
    <script>
    import ChildComponent from './ChildComponent.vue';
    
    export default {
     components: {
       ChildComponent
     },
     data() {
       return {
         message: 'Slot content in parent component.'
       };
     }
    }
    </script>
  2. 具名插槽
    在子组件中定义多个插槽,并使用slot属性指定插槽名称:

    <template>
     <div>
       <header>
         <slot name="header">Header content</slot>
       </header>
       <body>
         <slot name="body">Body content</slot>
       </body>
     </div>
    </template>
    
    <script>
    export default {
     data() {
       return {
         headerMessage: 'This is the header content.',
         bodyMessage: 'This is the body content.'
       };
     }
    }
    </script>

    在父组件中使用具名插槽:

    <template>
     <child-component>
       <template slot="header">
         <h1>{{ headerMessage }}</h1>
       </template>
       <template slot="body">
         <p>{{ bodyMessage }}</p>
       </template>
     </child-component>
    </template>
    
    <script>
    import ChildComponent from './ChildComponent.vue';
    
    export default {
     components: {
       ChildComponent
     },
     data() {
       return {
         headerMessage: 'Custom header content.',
         bodyMessage: 'Custom body content.'
       };
     }
    }
    </script>

动态组件和异步组件

动态组件允许根据不同的条件渲染不同的组件。异步组件则允许在需要时按需加载组件。

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

    <template>
     <div>
       <button @click="currentView = 'viewA'">View A</button>
       <button @click="currentView = 'viewB'">View B</button>
       <component :is="currentView"></component>
     </div>
    </template>
    
    <script>
    import ViewA from './ViewA.vue';
    import ViewB from './ViewB.vue';
    
    export default {
     components: {
       ViewA,
       ViewB
     },
     data() {
       return {
         currentView: 'ViewA'
       };
     }
    }
    </script>
  2. 异步组件
    使用工厂函数定义异步组件:

    const asyncComponent = () => import('./AsyncComponent.vue');

    在组件注册时使用异步组件:

    <template>
     <div>
       <async-component></async-component>
     </div>
    </template>
    
    <script>
    import asyncComponent from './AsyncComponent.vue';
    
    export default {
     components: {
       asyncComponent
     }
    }
    </script>

响应式原理

响应式系统概述

Vue3的响应式系统是实现数据绑定和依赖追踪的关键。Vue3的响应式系统基于Proxy对象实现,相比Vue2的Object.defineProperty实现了更高的性能和更灵活的数据结构处理。

  1. Ref:Ref是Vue3中的响应式引用类型,用于创建可响应的引用。通过ref包裹的数据可以在模板中直接使用,Vue会自动进行相应的依赖追踪和更新。

    import { ref } from 'vue';
    
    let count = ref(0);
    
    console.log(count.value);  // 0
    
    count.value++;
    console.log(count.value);  // 1
  2. Computed:计算属性是基于数据依赖进行缓存的属性。当依赖的数据发生变化时,计算属性会重新计算新的值。计算属性在性能上比方法更优,因为计算属性会被缓存,只有当依赖的数据发生变化时才会重新计算。

    import { ref, computed } from 'vue';
    
    let count = ref(0);
    
    let doubleCount = computed(() => {
     return count.value * 2;
    });
    
    console.log(doubleCount.value);  // 0
    
    count.value++;
    console.log(doubleCount.value);  // 2
  3. 响应式数据的使用
    在组件中使用响应式数据:

    <template>
     <div>
       <p>{{ count }}</p>
       <button @click="increment">
         Increment
       </button>
     </div>
    </template>
    
    <script>
    import { ref, computed } from 'vue';
    
    export default {
     setup() {
       let count = ref(0);
    
       let doubleCount = computed(() => {
         return count.value * 2;
       });
    
       let increment = () => {
         count.value++;
       };
    
       return {
         count,
         doubleCount,
         increment
       };
     }
    }
    </script>

路由与状态管理

Vue Router的基本使用

Vue Router是Vue应用中用于路由管理的官方库。它允许你定义不同的路由,每个路由映射到一个组件,从而实现单页面应用中的导航。

  1. 安装Vue Router
    使用npm或yarn安装Vue Router:
    npm install vue-router@next
  2. 创建Router实例
    创建一个路由器配置文件,定义路由映射:

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

    import { createApp } from 'vue';
    import App from './App.vue';
    import router from './router';
    
    const app = createApp(App);
    app.use(router);
    app.mount('#app');
  4. 使用路由
    在组件中使用<router-view>来渲染当前路由对应的组件:
    <template>
     <router-view></router-view>
    </template>

Vuex的状态管理

Vuex是Vue应用中的状态管理模式。它提供了一个集中式存储管理应用的所有组件中的状态,并允许按需派发状态变化,以满足各种不同的业务需求。

  1. 安装Vuex
    使用npm或yarn安装Vuex:
    npm install vuex@next
  2. 创建Vuex Store
    创建一个Vuex store,定义状态和操作:

    import { createStore } from 'vuex';
    
    export default createStore({
     state: {
       count: 0
     },
     mutations: {
       increment(state) {
         state.count++;
       }
     },
     actions: {
       increment({ commit }) {
         commit('increment');
       }
     },
     getters: {
       doubleCount: state => state.count * 2
     }
    });
  3. 注册Vuex Store
    在主应用文件中注册Vuex store:

    import { createApp } from 'vue';
    import App from './App.vue';
    import router from './router';
    import store from './store';
    
    const app = createApp(App);
    app.use(router);
    app.use(store);
    app.mount('#app');
  4. 使用Vuex Store
    在组件中使用Vuex store:

    <template>
     <div>
       <p>{{ count }}</p>
       <button @click="increment">
         Increment
       </button>
       <p>Double count: {{ doubleCount }}</p>
     </div>
    </template>
    
    <script>
    import { useStore } from 'vuex';
    
    export default {
     setup() {
       const store = useStore();
    
       const increment = () => {
         store.dispatch('increment');
       };
    
       return {
         count: computed(() => store.state.count),
         doubleCount: computed(() => store.getters.doubleCount),
         increment
       };
     }
    }
    </script>

路由守卫与Vuex插件

路由守卫是Vue Router中用来拦截导航操作的钩子函数,它可以用来执行一些预操作或后操作。

  1. 路由守卫
    在路由配置中定义路由守卫:

    import { createRouter, createWebHistory } from 'vue-router';
    import Home from './views/Home.vue';
    import About from './views/About.vue';
    
    const routes = [
     {
       path: '/',
       component: Home,
       beforeEnter: (to, from, next) => {
         console.log('Before entering Home');
         next();
       }
     },
     {
       path: '/about',
       component: About,
       beforeEnter: (to, from, next) => {
         console.log('Before entering About');
         next();
       }
     }
    ];
    
    const router = createRouter({
     history: createWebHistory(),
     routes
    });
    
    export default router;
  2. Vuex插件
    创建一个Vuex插件,用于扩展Vuex的功能:

    export default function (store) {
     store.subscribe((mutation, state) => {
       console.log('Mutation:', mutation);
       console.log('State:', state);
     });
    }

    在Vuex store中注册插件:

    import { createStore } from 'vuex';
    import myPlugin from './myPlugin';
    
    export default createStore({
     state: {
       count: 0
     },
     mutations: {
       increment(state) {
         state.count++;
       }
     },
     actions: {
       increment({ commit }) {
         commit('increment');
       }
     },
     getters: {
       doubleCount: state => state.count * 2
     },
     plugins: [myPlugin]
    });

实战项目

创建个人博客网站

创建一个简单的个人博客网站,包括文章列表、文章详情页和添加文章的功能。

  1. 项目结构

    my-blog/
    ├── public/
    │   └── index.html
    ├── src/
    │   ├── assets/
    │   ├── components/
    │   │   ├── ArticleList.vue
    │   │   ├── ArticleDetail.vue
    │   │   └── AddArticle.vue
    │   ├── router/
    │   │   └── index.js
    │   ├── store/
    │   │   └── index.js
    │   ├── App.vue
    │   └── main.js
    ├── package.json
    └── babel.config.js
  2. 安装依赖

    npm install
  3. 配置路由
    src/router/index.js中配置路由:

    import { createRouter, createWebHistory } from 'vue-router';
    import ArticleList from '../components/ArticleList.vue';
    import ArticleDetail from '../components/ArticleDetail.vue';
    import AddArticle from '../components/AddArticle.vue';
    
    const routes = [
     { path: '/', component: ArticleList },
     { path: '/article/:id', component: ArticleDetail },
     { path: '/add', component: AddArticle }
    ];
    
    const router = createRouter({
     history: createWebHistory(),
     routes
    });
    
    export default router;
  4. 创建组件

    • ArticleList.vue

      <template>
      <div>
       <h1>Article List</h1>
       <ul>
         <li v-for="article in articles" :key="article.id">
           <router-link :to="'/article/' + article.id">{{ article.title }}</router-link>
         </li>
       </ul>
       <router-link to="/add">Add Article</router-link>
      </div>
      </template>
      
      <script>
      import { ref, onMounted } from 'vue';
      import { useStore } from 'vuex';
      
      export default {
      setup() {
       const store = useStore();
      
       const articles = ref([]);
      
       const fetchArticles = async () => {
         // Fetch articles from API or local storage
         // For now, let's use a dummy data array
         articles.value = [
           { id: 1, title: 'Article 1' },
           { id: 2, title: 'Article 2' }
         ];
       };
      
       onMounted(() => {
         fetchArticles();
       });
      
       return {
         articles
       };
      }
      }
      </script>
    • ArticleDetail.vue

      <template>
      <div>
       <h1>Article Detail</h1>
       <router-link to="/">Back to List</router-link>
       <h2>{{ article.title }}</h2>
       <p>{{ article.content }}</p>
      </div>
      </template>
      
      <script>
      import { useRoute, useRouter } from 'vue-router';
      import { ref, onMounted } from 'vue';
      import { useStore } from 'vuex';
      
      export default {
      setup() {
       const route = useRoute();
       const router = useRouter();
       const store = useStore();
      
       const article = ref(null);
      
       const fetchArticle = async () => {
         const id = route.params.id;
         // Fetch article from API or local storage
         // For now, let's use a dummy data object
         article.value = {
           id: id,
           title: 'Article ' + id,
           content: 'Content ' + id
         };
       };
      
       onMounted(() => {
         fetchArticle();
       });
      
       const deleteArticle = () => {
         store.dispatch('deleteArticle', article.value);
         router.push('/');
       };
      
       return {
         article,
         deleteArticle
       };
      }
      }
      </script>
    • AddArticle.vue

      <template>
      <div>
       <h1>Add Article</h1>
       <form @submit.prevent="addArticle">
         <label>
           Title:
           <input v-model="title" />
         </label>
         <label>
           Content:
           <textarea v-model="content"></textarea>
         </label>
         <button type="submit">Add</button>
       </form>
       <router-link to="/">Back to List</router-link>
      </div>
      </template>
      
      <script>
      import { ref, onMounted } from 'vue';
      import { useStore } from 'vuex';
      
      export default {
      setup() {
       const store = useStore();
      
       const title = ref('');
       const content = ref('');
      
       const addArticle = () => {
         store.dispatch('addArticle', { title: title.value, content: content.value });
         title.value = '';
         content.value = '';
       };
      
       return {
         title,
         content,
         addArticle
       };
      }
      }
      </script>
  5. 配置Vuex
    src/store/index.js中配置Vuex store:

    import { createStore } from 'vuex';
    import axios from 'axios';
    
    export default createStore({
     state: {
       articles: []
     },
     mutations: {
       setArticles(state, articles) {
         state.articles = articles;
       },
       deleteArticle(state, article) {
         state.articles = state.articles.filter(a => a.id !== article.id);
       }
     },
     actions: {
       fetchArticles({ commit }) {
         axios.get('/api/articles')
           .then(response => {
             commit('setArticles', response.data);
           });
       },
       addArticle({ commit }, article) {
         axios.post('/api/articles', article)
           .then(response => {
             commit('setArticles', [...state.articles, response.data]);
           });
       },
       deleteArticle({ commit }, article) {
         axios.delete(`/api/articles/${article.id}`)
           .then(response => {
             commit('deleteArticle', article);
           });
       }
     },
     getters: {
       articles: state => state.articles
     }
    });

集成API与数据展示

集成后端API进行数据的获取、添加和删除操作。

  1. 后端API
    使用一个简单的后端API来模拟数据操作。例如,可以使用Node.js和Express来搭建后端API。

    const express = require('express');
    const app = express();
    const articles = [];
    
    app.get('/api/articles', (req, res) => {
     res.json(articles);
    });
    
    app.post('/api/articles', (req, res) => {
     const article = req.body;
     articles.push(article);
     res.json(article);
    });
    
    app.delete('/api/articles/:id', (req, res) => {
     const id = parseInt(req.params.id);
     const index = articles.findIndex(article => article.id === id);
     if (index > -1) {
       articles.splice(index, 1);
       res.json({ success: true });
     } else {
       res.status(404).json({ success: false });
     }
    });
    
    app.listen(3000, () => {
     console.log('Server is running on port 3000');
    });
  2. 前端集成
    在前端代码中集成后端API进行数据操作。

    import axios from 'axios';
    
    export default {
     fetchArticles() {
       return axios.get('/api/articles');
     },
     addArticle(article) {
       return axios.post('/api/articles', article);
     },
     deleteArticle(article) {
       return axios.delete(`/api/articles/${article.id}`);
     }
    };

部署与上线

部署Vue应用到生产环境需要进行一些额外的配置,包括构建优化和环境变量设置。

  1. 构建优化
    使用vue-cli-service进行构建:

    npm run build

    这会生成一个dist目录,里面包含了生产环境下的静态文件。

  2. 环境变量设置
    vue.config.js中配置环境变量:

    module.exports = {
     configureWebpack: {
       devServer: {
         publicPath: process.env.BASE_URL
       },
       resolve: {
         alias: {
           '@': '/path/to/your/project'
         }
       }
     },
     css: {
       extract: true
     },
     chainWebpack: config => {
       config.plugin('define').tap(args => {
         return [
           args[0].concat([
             ['process.env.NODE_ENV', JSON.stringify('production')]
           ])
         ];
       });
     }
    };
  3. 部署到服务器
    将构建好的文件上传到服务器,并配置Web服务器(如Nginx)来提供静态内容:

    scp -r dist/* user@yourserver:/path/to/your/server/public

    配置Nginx的server块来提供服务:

    server {
     listen 80;
     server_name yourdomain.com;
    
     location / {
       root /path/to/your/server/public;
       try_files $uri /index.html;
     }
    }
点击查看更多内容
TA 点赞

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

评论

作者其他优质文章

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

100积分直接送

付费专栏免费学

大额优惠券免费领

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

举报

0/150
提交
取消