这是一篇vue3 的详细教程

在这里插入图片描述

Vue 3 详细教程

一、Vue 3 简介

Vue.js 是一款流行的 JavaScript 前端框架,用于构建用户界面。Vue 3 是其最新版本,带来了许多新特性和性能优化,使开发更加高效和灵活。

二、环境搭建

  1. 安装 Node.js
    • 前往Node.js 官方网站下载并安装适合你操作系统的版本。安装完成后,在终端或命令提示符中输入node -vnpm -v,确保 Node.js 和 npm(包管理器)已成功安装并显示相应版本号。
  2. 创建 Vue 项目
    • 打开终端或命令提示符,进入你想要创建项目的目录。
    • 运行npm install -g @vue/cli全局安装 Vue CLI(命令行界面工具)。如果之前安装过旧版本的 Vue CLI,可能需要先卸载npm uninstall -g vue-cli
    • 运行vue create 项目名称创建一个新的 Vue 3 项目。在创建过程中,你可以选择默认的配置(babel、eslint 等),也可以手动选择需要的特性,如 Vue Router(路由管理)、Vuex(状态管理)等。
    • 例如,选择手动配置,按下回车键后,会出现一系列选项让你勾选。你可以根据项目需求选择,比如选择 Vue Router 和 Vuex,然后使用空格键勾选,回车键确认。
    • 等待项目创建完成,进入项目目录cd 项目名称
    • 运行npm run serve启动开发服务器,在浏览器中访问http://localhost:8080/,你将看到 Vue 项目的默认页面。

三、Vue 3 基础语法

  1. 模板语法

    • 插值表达式
      • 在 Vue 的模板中,你可以使用{{}}来插入动态数据。例如:
        <template>
          <div>
            <h1>{{ message }}</h1>
          </div>
        </template>
        
        <script>
          import { defineComponent } from 'vue';
          export default defineComponent({
            name: 'App',
            data() {
              return {
                message: 'Hello Vue 3!'
              };
            }
          });
        </script>
        
      • 这里的message是在组件的数据中定义的,插值表达式会将其值显示在h1标签中。
    • 指令
      • v-bind:用于动态绑定 HTML 属性。例如,绑定一个元素的src属性:
        <template>
          <img v-bind:src="imageUrl" alt="图片">
        </template>
        
        <script>
          import { defineComponent } from 'vue';
          export default defineComponent({
            name: 'App',
            data() {
              return {
                imageUrl: 'https://example.com/image.jpg'
              };
            }
          });
        </script>
        
        也可以简写为:,如<img :src="imageUrl" alt="图片">
      • v-if 和 v-else:用于条件渲染。当条件为真时,显示v-if所在的元素,否则显示v-else所在的元素。
        <template>
          <div>
            <p v-if="showText">这是一段显示的文本</p>
            <p v-else>这段文本不显示(当条件不满足时)</p>
          </div>
        </template>
        
        <script>
          import { defineComponent } from 'vue';
          export default defineComponent({
            name: 'App',
            data() {
              return {
                showText: true
              };
            }
          });
        </script>
        
      • v-for:用于循环渲染列表。例如,渲染一个数组中的数据:
        <template>
          <ul>
            <li v-for="item in items" :key="item.id">{{ item.name }}</li>
          </ul>
        </template>
        
        <script>
          import { defineComponent } from 'vue';
          export default defineComponent({
            name: 'App',
            data() {
              return {
                items: [
                  { id: 1, name: 'Item 1' },
                  { id: 2, name: 'Item 2' },
                  { id: 3, name: 'Item 3' }
                ]
              };
            }
          });
        </script>
        
      • 这里的key是一个特殊的属性,用于给 Vue 提供一个唯一标识,以便更高效地更新和渲染列表元素。
  2. 响应式数据

    • Vue 3 使用refreactive来创建响应式数据。
    • ref
      • 用于创建基本类型(如数字、字符串、布尔值等)的响应式数据。例如:
        <template>
          <div>
            <p>{{ counter }}</p>
            <button @click="increment">增加</button>
          </div>
        </template>
        
        <script>
          import { defineComponent, ref } from 'vue';
          export default defineComponent({
            name: 'App',
            setup() {
              const counter = ref(0);
              const increment = () => {
                counter.value++;
              };
              return {
                counter,
                increment
              };
            }
          });
        </script>
        
      • 这里counter是一个响应式变量,通过ref创建。在setup函数中,修改counter.value会触发视图的更新。
    • reactive
      • 用于创建对象类型的响应式数据。例如:
        <template>
          <div>
            <p>{{ user.name }} - {{ user.age }}</p>
            <button @click="updateUser">更新用户信息</button>
          </div>
        </template>
        
        <script>
          import { defineComponent, reactive } from 'vue';
          export default defineComponent({
            name: 'App',
            setup() {
              const user = reactive({
                name: 'John',
                age: 30
              });
              const updateUser = () => {
                user.name = 'Jane';
                user.age = 35;
              };
              return {
                user,
                updateUser
              };
            }
          });
        </script>
        
      • reactive创建的对象,其属性的修改也会自动反映在视图中。
  3. 事件处理

    • 在 Vue 中,可以使用v-on指令或其简写@来监听事件并执行相应的方法。例如:
    <template>
      <button @click="handleClick">点击我</button>
    </template>
    
    <script>
      import { defineComponent } from 'vue';
      export default defineComponent({
        name: 'App',
        methods: {
          handleClick() {
            console.log('按钮被点击了!');
          }
        }
      });
    </script>
    
    • 你还可以传递参数给事件处理方法。例如:
    <template>
      <button @click="handleClickWithParam(123)">点击并传递参数</button>
    </template>
    
    <script>
      import { defineComponent } from 'vue';
      export default defineComponent({
        name: 'App',
        methods: {
          handleClickWithParam(param) {
            console.log('传递的参数是:', param);
          }
        }
      });
    </script>
    

四、Vue Router(路由管理)

  1. 安装和配置
    • 首先,在你的 Vue 3 项目中安装vue-router。在项目目录下的终端中运行npm install vue-router@4(这里安装的是 Vue Router 4 版本,适配 Vue 3)。
    • 然后,在项目的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;
    
    • 在上述代码中,我们定义了两个路由:/(首页)和/about(关于页面),分别对应Home.vueAbout.vue组件。
    • 接下来,需要在main.js文件中引入路由并将其挂载到 Vue 实例上。修改main.js文件如下:
    import { createApp } from 'vue';
    import App from './App.vue';
    import router from './router/index.js';
    
    const app = createApp(App);
    app.use(router);
    app.mount('#app');
    
  2. 路由导航
    • 在模板中,可以使用<router-link>组件来进行页面导航。例如:
    <template>
      <div>
        <nav>
          <router-link to="/">首页</router-link>
          <router-link to="/about">关于</router-link>
        </nav>
        <router-view></router-view>
      </div>
    </template>
    
    • <router-link>会渲染成一个带有链接功能的元素,点击它会导航到对应的路由页面。<router-view>是一个占位符,用于显示当前路由对应的组件内容。

五、Vuex(状态管理)

  1. 安装和配置
    • 在项目目录下的终端中运行npm install vuex@next(安装 Vuex 的适配 Vue 3 的版本)。
    • src目录下创建一个store文件夹,并在其中创建一个index.js文件用于配置 Vuex 存储。
    • 示例代码如下:
    import { createStore } from 'vuex';
    
    const store = createStore({
      state() {
        return {
          count: 0
        };
      },
      mutations: {
        increment(state) {
          state.count++;
        }
      },
      actions: {
        incrementAsync({ commit }) {
          setTimeout(() => {
            commit('increment');
          }, 1000);
        }
      },
      getters: {
        doubleCount(state) {
          return state.count * 2;
        }
      }
    });
    
    export default store;
    
    • 在上述代码中,state定义了应用的初始状态,这里是一个count变量初始值为 0。mutations用于定义更改状态的方法,这里的increment方法会将count加 1。actions用于处理异步操作,这里的incrementAsync会在 1 秒后调用increment mutation。getters用于计算派生状态,这里的doubleCount返回count的两倍。
  2. 在组件中使用 Vuex
    • 在 Vue 组件中,可以通过this.$store来访问 Vuex 存储中的状态和方法。例如:
    <template>
      <div>
        <p>当前计数:{{ count }}</p>
        <p>双倍计数:{{ doubleCount }}</p>
        <button @click="increment">增加计数</button>
        <button @click="incrementAsync">异步增加计数</button>
      </div>
    </template>
    
    <script>
      import { mapState, mapMutations, mapActions } from 'vuex';
      export default {
        computed: {
         ...mapState(['count', 'doubleCount'])
        },
        methods: {
         ...mapMutations(['increment']),
         ...mapActions(['incrementAsync'])
        }
      };
    </script>
    
    • 在上述代码中,通过mapStatecountdoubleCount映射到组件的计算属性中,这样在模板中就可以直接使用。通过mapMutationsincrement mutation 方法映射到组件的方法中,通过mapActionsincrementAsync action 方法映射到组件的方法中,以便在模板中通过按钮点击调用。

六、组件通信

  1. 父子组件通信
    • 父传子
      • 在父组件中,可以通过属性传递的方式将数据传递给子组件。例如:
        <!-- 父组件 -->
        <template>
          <div>
            <child-component :message="parentMessage"></child-component>
          </div>
        </template>
        
        <script>
          import { defineComponent } from 'vue';
          import ChildComponent from './ChildComponent.vue';
          export default defineComponent({
            name: 'ParentComponent',
            components: { ChildComponent },
            data() {
              return {
                parentMessage: '这是来自父组件的消息'
              };
            }
          });
        </script>
        
        在子组件中,可以通过props选项接收父组件传递的数据:
        <!-- 子组件 -->
        <template>
          <div>
            <p>{{ message }}</p>
          </div>
        </template>
        
        <script>
          import { defineComponent } from 'vue';
          export default defineComponent({
            name: 'ChildComponent',
            props: {
              message: String
            }
          });
        </script>
        
    • 子传父
      • 子组件可以通过触发自定义事件并传递数据给父组件。例如:
        <!-- 子组件 -->
        <template>
          <div>
            <button @click="sendMessageToParent">向父组件发送消息</button>
          </div>
        </template>
        
        <script>
          import { defineComponent } from 'vue';
          export default defineComponent({
            name: 'ChildComponent',
            methods: {
              sendMessageToParent() {
                this.$emit('childMessage', '这是来自子组件的消息');
              }
            }
          });
        </script>
        
        在父组件中,监听子组件触发的事件并接收数据:
        <!-- 父组件 -->
        <template>
          <div>
            <child-component @childMessage="handleChildMessage"></child-component>
            <p>{{ receivedMessage }}</p>
          </div>
        </template>
        
        <script>
          import { defineComponent } from 'vue';
          import ChildComponent from './ChildComponent.vue';
          export default defineComponent({
            name: 'ParentComponent',
            components: { ChildComponent },
            data() {
              return {
                receivedMessage: ''
              };
            },
            methods: {
              handleChildMessage(message) {
                this.receivedMessage = message;
              }
            }
          });
        </script>
        
  2. 兄弟组件通信
    • 可以通过使用 Vuex 来实现兄弟组件之间的通信。例如,一个兄弟组件修改了 Vuex 中的状态,另一个兄弟组件可以通过mapState获取到更新后的状态。
    • 或者,可以创建一个事件总线(Event Bus)来实现兄弟组件通信。首先,创建一个事件总线文件,例如src/bus.js
    import { mitt } from 'mitt';
    
    const bus = mitt();
    
    export default bus;
    
    • 在需要发送事件的兄弟组件中:
    <template>
      <div>
        <button @click="sendMessageToBrother">向兄弟组件发送消息</button>
      </div>
    </template>
    
    <script>
      import bus from '../bus.js';
      export default {
        methods: {
          sendMessageToBrother() {
            bus.emit('brotherMessage', '这是来自一个兄弟组件的消息');
          }
        }
      };
    </script>
    
    • 在需要接收事件的兄弟组件中:
    <template>
      <div>
        <p>{{ receivedMessage }}</p>
      </div>
    </template>
    
    <script>
      import bus from '../bus.js';
      export default {
        data() {
          return {
            receivedMessage: ''
          };
        },
        mounted() {
          bus.on('brotherMessage', (message) => {
            this.receivedMessage = message;
          });
        },
        beforeUnmount() {
          bus.off('brotherMessage');
        }
      };
    </script>
    
    • 在上述代码中,mounted钩子中监听brotherMessage事件,beforeUnmount钩子中取消监听,以避免内存泄漏。

七、生命周期钩子

Vue 3 中的组件有一系列生命周期钩子,它们在组件的不同阶段被调用。

  1. beforeCreate
    • 在实例初始化之后,数据观测(data option 的处理)和事件配置(event / watch 选项的处理)之前被调用。这个阶段通常用于在组件实例创建之前进行一些初始化工作,但此时数据和响应式系统尚未初始化,所以不能访问datacomputedmethods中的数据和方法。
    • 示例用法:
      import { defineComponent } from 'vue';
      export default defineComponent({
        name: 'MyComponent',
        beforeCreate() {
          console.log('beforeCreate - 组件实例初始化后,数据观测和事件配置前调用');
        }
      });
      
  2. created
    • 在实例创建完成后被立即调用。此时,组件实例已经完成了数据观测、属性和方法的计算,但尚未挂载到 DOM 上。可以在这里进行一些需要访问响应式数据的初始化操作,比如发起异步数据请求等。
    • 示例用法:
      import { defineComponent, ref } from 'vue';
      export default defineComponent({
        name: 'MyComponent',
        data() {
          return {
            message: '初始消息'
          };
        },
        created() {
          console.log('created - 组件实例创建完成,数据观测和计算属性等初始化后调用');
          console.log('初始消息:', this.message);
          // 可以在这里发起异步请求获取数据
          this.fetchData();
        },
        methods: {
          fetchData() {
            // 模拟异步请求
            setTimeout(() => {
              this.message = '获取到的数据';
            }, 1000);
          }
        }
      });
      
  3. beforeMount
    • 在挂载开始之前被调用。此时,模板已经编译完成,但尚未渲染到 DOM 中。可以在这个阶段进行一些最后的准备工作,比如手动操作 DOM 等(但不建议这样做,因为 Vue 的理念是尽量避免直接操作 DOM,除非有特殊需求)。
    • 示例用法:
      import { defineComponent } from 'vue';
      export default defineComponent({
        name: 'MyComponent',
        beforeMount() {
          console.log('beforeMount - 挂载开始之前调用');
        }
      });
      
  4. mounted
    • 在组件挂载到 DOM 后被调用。此时,组件已经完全渲染到页面上,可以在这个阶段进行一些与 DOM 操作相关的操作,比如获取 DOM 元素、初始化第三方库等。这个钩子函数通常用于在组件渲染完成后执行一些需要依赖 DOM 的操作。
    • 示例用法:
      import { defineComponent, ref } from 'vue';
      export default defineComponent({
        name: 'MyComponent',
        mounted() {
          console.log('mounted - 组件挂载到DOM后调用');
          const element = document.getElementById('myElement');
          if (element) {
            // 对元素进行操作
            element.style.color ='red';
          }
          // 初始化第三方库
          this.initThirdPartyLibrary();
        },
        methods: {
          initThirdPartyLibrary() {
            // 假设这里是初始化一个第三方图表库的代码
            // 例如:Chart.js 的初始化
            const ctx = document.getElementById('chartCanvas').getContext('2d');
            new Chart(ctx, {
              type: 'bar',
              data: {
                labels: ['January', 'February', 'March'],
                datasets: [{
                  label: 'Sales',
                  data: [10, 20, 30],
                  backgroundColor: 'rgba(75, 192, 192, 0.2)',
                  borderColor: 'rgba(75, 192, 192, 1)',
                  borderWidth: 1
                }]
              }
            });
          }
        }
      });
      
  5. beforeUpdate
    • 在数据更新时(响应式数据发生变化),但在虚拟 DOM 重新渲染和打补丁之前被调用。可以在这个钩子中访问到更新前的状态,可以用于在更新 DOM 之前进行一些准备工作,比如记录当前状态等。
    • 示例用法:
      import { defineComponent, ref } from 'vue';
      export default defineComponent({
        name: 'MyComponent',
        data() {
          return {
            count: 0
          };
        },
        beforeUpdate() {
          console.log('beforeUpdate - 数据更新前调用');
          console.log('更新前的计数:', this.count);
        },
        methods: {
          incrementCount() {
            this.count++;
          }
        }
      });
      
  6. updated
    • 在数据更新(响应式数据发生变化)导致的虚拟 DOM 重新渲染和打补丁之后被调用。此时,DOM 已经更新为最新的状态,可以在这个阶段进行一些与更新后相关的操作,比如重新获取 DOM 元素的新状态等。但需要注意的是,在这个钩子中频繁操作 DOM 可能会导致性能问题,因为它可能会在一个更新周期内被多次调用。
    • 示例用法:
      import { defineComponent, ref } from 'vue';
      export default defineComponent({
        name: 'MyComponent',
        data() {
          return {
            count: 0
          };
        },
        updated() {
          console.log('updated - 数据更新后,虚拟DOM重新渲染和打补丁后调用');
          console.log('更新后的计数:', this.count);
          const element = document.getElementById('countDisplay');
          if (element) {
            element.textContent = `当前计数:${this.count}`;
          }
        },
        methods: {
          incrementCount() {
            this.count++;
          }
        }
      });
      
  7. beforeUnmount
    • 在组件卸载之前被调用。可以在这个阶段进行一些清理工作,比如取消定时器、解绑事件监听器、清除全局变量等,以防止内存泄漏和不必要的副作用。
    • 示例用法:
      import { defineComponent, ref } from 'vue';
      export default defineComponent({
        name: 'MyComponent',
        data() {
          return {
            timer: null
          };
        },
        mounted() {
          this.timer = setInterval(() => {
            console.log('定时任务执行');
          }, 1000);
        },
        beforeUnmount() {
          console.log('beforeUnmount - 组件卸载之前调用');
          clearInterval(this.timer);
          this.timer = null;
          // 假设这里有解绑事件监听器的代码
          window.removeEventListener('resize', this.handleResize);
        },
        methods: {
          handleResize() {
            // 处理窗口大小调整的逻辑
          }
        }
      });
      
  8. unmounted
    • 在组件卸载之后被调用。此时,组件的所有实例绑定和事件监听器都已经被移除,DOM 元素也已经被销毁。可以在这个阶段进行一些最后的清理工作,比如进行一些日志记录等。
    • 示例用法:
      import { defineComponent } from 'vue';
      export default defineComponent({
        name: 'MyComponent',
        unmounted() {
          console.log('unmounted - 组件卸载之后调用');
        }
      });
      

理解和正确使用这些生命周期钩子对于优化组件的性能、管理组件的状态以及处理各种逻辑场景非常重要。在实际开发中,需要根据具体的需求选择合适的生命周期钩子来执行相应的代码。

八、组合式 API

Vue 3 引入了组合式 API,它提供了一种更灵活和逻辑复用性更强的方式来组织组件的逻辑。

  1. setup 函数
    • setup是组合式 API 的核心函数,在组件创建之前执行,用于初始化响应式数据、定义方法等。它接收两个参数:propscontext
    • props是父组件传递给子组件的属性对象,是响应式的。可以通过解构的方式获取需要的属性。
    • context包含了一些其他的上下文信息,如attrs(非 props 属性集合)、slots(插槽对象)和emit(用于触发自定义事件的方法)等。
    • 示例代码:
      <template>
        <div>
          <p>{{ message }}</p>
          <button @click="handleClick">点击修改消息</button>
        </div>
      </template>
      
      <script>
        import { defineComponent, ref } from 'vue';
        export default defineComponent({
          name: 'MyComponent',
          props: {
            initialMessage: String
          },
          setup(props, context) {
            // 使用ref创建响应式数据
            const message = ref(props.initialMessage);
            const handleClick = () => {
              message.value = '新的消息';
              // 触发自定义事件通知父组件
              context.emit('messageUpdated', message.value);
            };
            return {
              message,
              handleClick
            };
          }
        });
      </script>
      
  2. 响应式函数
    • 除了ref用于创建基本类型的响应式数据外,还有reactive用于创建对象类型的响应式数据,以及computed用于创建计算属性。
    • reactive示例:
      import { reactive } from 'vue';
      const state = reactive({
        count: 0,
        name: 'John'
      });
      // 修改响应式对象的属性
      state.count++;
      state.name = 'Jane';
      
    • computed示例:
      import { reactive, computed } from 'vue';
      const state = reactive({
        count: 0
      });
      // 创建计算属性
      const doubleCount = computed(() => state.count * 2);
      console.log(doubleCount.value); // 初始值为0
      state.count++;
      console.log(doubleCount.value); // 值变为2
      
  3. 自定义钩子
    • 可以创建自定义钩子来封装可复用的逻辑。例如,创建一个用于获取数据的自定义钩子:
      import { ref, onMounted } from 'vue';
      export function useFetchData(apiUrl) {
        const data = ref(null);
        const loading = ref(true);
        const error = ref(null);
      
        onMounted(async () => {
          try {
            const response = await fetch(apiUrl);
            if (!response.ok) {
              throw new Error('网络请求失败');
            }
            data.value = await response.json();
          } catch (err) {
            error.value = err;
          } finally {
            loading.value = false;
          }
        });
      
        return {
          data,
          loading,
          error
        };
      }
      
    • 在组件中使用自定义钩子:
      <template>
        <div>
          <p v-if="loading">正在加载数据...</p>
          <p v-if="error">{{ error }}</p>
          <ul v-if="data">
            <li v-for="item in data" :key="item.id">{{ item.name }}</li>
          </ul>
        </div>
      </template>
      
      <script>
        import { defineComponent } from 'vue';
        import { useFetchData } from './customHooks.js'; // 假设自定义钩子在这个文件中
        export default defineComponent({
          name: 'DataComponent',
          setup() {
            const { data, loading, error } = useFetchData('https://api.example.com/data');
            return {
              data,
              loading,
              error
            };
          }
        });
      </script>
      

九、Teleport 组件

Teleport是 Vue 3 中一个很有用的特性,它允许你将一个组件的模板内容渲染到 DOM 中的其他位置,而不是默认的组件挂载点。

  1. 基本用法
    • 例如,有一个模态框组件,你可能希望它的内容渲染到页面的body元素上,而不是组件所在的位置,这样可以避免模态框的样式受到组件自身布局的限制。
    • 首先,在模板中使用Teleport组件:
      <template>
        <Teleport to="body">
          <div class="modal">
            <h2>这是一个模态框</h2>
            <p>模态框的内容</p>
            <button @click="closeModal">关闭</button>
          </div>
        </Teleport>
      </template>
      
      <script>
        import { defineComponent } from 'vue';
        export default defineComponent({
          name: 'ModalComponent',
          data() {
            return {
              isModalOpen: true
            };
          },
          methods: {
            closeModal() {
              this.isModalOpen = false;
            }
          }
        });
      </script>
      
    • 在上述代码中,Teleport组件将内部的div.modal内容渲染到了body元素上。你可以通过修改to属性的值来指定将内容渲染到其他的 DOM 元素上,比如一个特定的div元素的 ID。
  2. 与 CSS 样式结合
    • 当使用Teleport时,需要注意样式的应用。因为内容被渲染到了其他位置,所以可能需要特别处理样式。
    • 可以在全局样式中或者在组件的style标签中使用适当的选择器来确保模态框的样式正确应用。例如:
      /* 全局样式 */
      body.modal {
        position: fixed;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        background-color: white;
        padding: 20px;
        border-radius: 5px;
        box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
      }
      
    • 或者在组件的style标签中使用scoped样式(如果只想应用于当前组件的模态框):
      <template>
        <!-- 模态框内容等 -->
      </template>
      
      <script>
        // 组件脚本
      </script>
      
      <style scoped>
      .modal {
         /* 模态框的样式与上面类似 */
       }
      </style>
      

十、Suspense 组件

Suspense组件用于处理异步加载的组件,它可以提供一个更友好的加载状态显示方式,当异步组件正在加载时,可以显示一个加载占位符,加载完成后再显示实际的组件内容。

  1. 使用场景
    • 例如,当你有一个组件需要从服务器获取大量数据后才能渲染,在数据获取过程中,页面可能会出现空白或者加载缓慢的情况。使用Suspense可以在这个过程中显示一个加载提示,提升用户体验。
  2. 基本用法
    • 首先,创建一个异步组件。假设我们有一个AsyncComponent,它在setup函数中模拟异步数据获取:
      // AsyncComponent.vue
      import { defineComponent, ref } from 'vue';
      export default defineComponent({
        name: 'AsyncComponent',
        async setup() {
          const data = ref(null);
          // 模拟异步获取数据,这里使用 setTimeout 代替实际的异步请求
          await new Promise((resolve) => setTimeout(resolve, 2000));
          data.value = '异步数据获取成功';
          return {
            data
          };
        },
        template: '<div>{{ data }}</div>'
      });
      
    • 然后,在使用这个异步组件的父组件中,使用Suspense包裹:
      <template>
        <Suspense>
          <template #default>
            <AsyncComponent />
          </template>
          <template #fallback>
            <div>正在加载...</div>
          </template>
        </Suspense>
      </template>
      
      <script>
        import { defineComponent } from 'vue';
        import AsyncComponent from './AsyncComponent.vue';
        export default defineComponent({
          name: 'ParentComponent',
          components: {
            AsyncComponent
          }
        });
      </script>
      
    • 在上述代码中,#default插槽中是要异步加载的组件(AsyncComponent),#fallback插槽中是当异步组件正在加载时显示的内容(这里是一个简单的“正在加载…”提示)。

十一、性能优化

  1. 代码分割
    • 在大型 Vue 应用中,为了提高页面加载速度,可以使用代码分割技术。Vue CLI 已经内置了对代码分割的支持。例如,对于一些大型的库或者模块,可以将其分割成单独的 chunk(代码块),在需要时再进行加载。
    • 在路由配置中,可以使用import()函数进行动态导入路由组件,这样相关的代码会被自动分割成单独的 chunk。
    • 示例代码(在router/index.js中):
      const routes = [
        {
          path: '/',
          name: 'Home',
          component: () => import('../views/Home.vue') // 动态导入Home.vue组件
        },
        {
          path: '/about',
          name: 'About',
          component: () => import('../views/About.vue') // 动态导入About.vue组件
        }
      ];
      
  2. 虚拟列表(Virtual List)
    • 当处理大量列表数据时,例如渲染一个包含数千条记录的列表,可能会导致性能问题。可以使用虚拟列表技术,只渲染当前可见区域的列表项,提高渲染性能。
    • 可以使用第三方库如vue-virtual-scroller来实现虚拟列表。首先,安装该库:npm install vue-virtual-scroller
    • 然后,在组件中使用:
      <template>
        <div>
          <VirtualList :data="bigDataList" :item-size="50">
            <template #default="{ item }">
              <div>{{ item.name }}</div>
            </template>
          </VirtualList>
        </div>
      </template>
      
      <script>
        import { defineComponent } from 'vue';
        import VirtualList from 'vue-virtual-scroller';
        export default defineComponent({
          name: 'ListComponent',
          components: {
            VirtualList
          },
          data() {
            return {
              bigDataList: [] // 假设这是一个包含大量数据的数组
            };
          },
          async mounted() {
            // 模拟获取大量数据
            const response = await fetch('https://api.example.com/largeData');
            const data = await response.json();
            this.bigDataList = data;
          }
        });
      </script>
      
    • 在上述代码中,VirtualList组件根据列表项的高度(item-size)和当前可见区域来计算需要渲染的列表项,大大提高了性能,特别是在处理长列表时。
  3. 避免不必要的重新渲染
    • Vue 的响应式系统会自动跟踪数据的变化并触发组件的重新渲染。但有时候,一些不必要的数据变化可能会导致组件频繁重新渲染,影响性能。
    • 可以使用Object.freeze()方法来冻结一些不会变化的数据对象,避免 Vue 对其进行深度响应式追踪。例如:
      import { defineComponent, ref } from 'vue';
      export default defineComponent({
        name: 'MyComponent',
        setup() {
          const staticData = ref({ name: '静态数据', value: 123 });
          Object.freeze(staticData.value); // 冻结数据对象
          const dynamicData = ref({ count: 0 });
          const incrementCount = () => {
            dynamicData.value.count++;
          };
          return {
            staticData,
            dynamicData,
            incrementCount
          };
        }
      });
      
    • 在上述代码中,staticData中的数据不会被 Vue 深度追踪,因为它被冻结了,只有dynamicData中的数据变化会导致组件重新渲染,这样可以提高性能,特别是当有大量静态数据且不需要频繁更新时。

十二、部署

  1. 构建生产版本
    • 在项目开发完成后,需要构建生产版本的代码。在项目目录下的终端中运行npm run build。这会将项目中的代码进行压缩、优化等处理,生成适合部署到生产环境的文件。
    • 构建完成后,会在项目目录下生成一个dist文件夹,其中包含了index.html文件以及jscss等静态资源文件。
  2. 部署到服务器
    • 部署的方式有很多种,常见的有部署到云服务器(如阿里云、腾讯云等)、虚拟主机等。
    • 以部署到 Nginx 服务器为例:
      • dist文件夹中的所有文件上传到服务器的指定目录(例如/var/www/html/my-vue-app)。
      • 配置 Nginx 服务器,创建一个新的站点配置文件(例如/etc/nginx/sites-available/my-vue-app.conf),内容如下:
        server {
          listen 80;
          server_name your_domain.com; // 替换为你的域名
        
          root /var/www/html/my-vue-app;
        
          location / {
            try_files $uri $uri/ /index.html;
          }
        }
        
      • 然后将该配置文件链接到sites-enabled目录下:sudo ln -s /etc/nginx/sites-available/my-vue-app.conf /etc/nginx/sites-enabled/
      • 最后,重启 Nginx 服务器:sudo service nginx restart
      • 现在,你就可以通过浏览器访问你的域名来查看部署的 Vue 应用了。

大家认真阅读!早日腾飞!一键三连!!!!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/900643.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网站的SSL证书快到期了怎么办?怎么续签?

网站的SSL证书即将到期时&#xff0c;需要续签一个新的证书以保持网站的安全性和信任度。以下是续签SSL证书的一般步骤&#xff1a; 1. 选择证书提供商 如果您之前使用的是免费证书&#xff0c;您可以选择继续使用同一提供商的免费证书服务进行续签。如果您需要更高级别的证书…

Python:背景知识及环境安装

一、计算机的基础概念 1.1 什么是计算机&#xff1f; 最早我们有计算器&#xff0c;但是他只能完成算数运算的功能 而计算机能完成的工作有&#xff1a; &#xff08;1&#xff09;算术运算 &#xff08;2&#xff09;逻辑判断 &#xff08;3&#xff09;数据存储 &#xff08…

【AI学习】Mamba学习(十二):深入理解S4模型

#1024程序员节&#xff5c;征文# HiPPO的学习暂告一段落&#xff0c;按照“HiPPO->S4->Mamba 演化历程”&#xff0c;接着学习S4。 S4对应的论文&#xff1a;《Efficiently Modeling Long Sequences with Structured State Spaces》 文章链接&#xff1a;https://ar5iv…

Two output files share the same path but have different contents

报错 ✘ [ERROR] Two output files share the same path but have different contents: node_modules/.vite/deps_temp_c5811052/three_examples_jsm_controls_orbitControls__js.js7:48:33 PM [vite] error while updating dependencies: Error: Build failed with 1 error: …

7款视频转换器大测评!哪款是最适合你的视频格式转换器?

视频已成为我们生活中不可或缺的一部分&#xff0c;但不同的设备、平台和软件往往支持不同的视频格式&#xff0c;这给我们的视频分享、编辑和播放带来了不少困扰。因此&#xff0c;一款高效、易用的视频格式转换器成为了许多人的必备工具。本文将从软件界面、功能特性、难易程…

利用移动式三维扫描技术创建考古文物的彩色纹理网格【上海沪敖3D】

文章来源于蔡司工业质量解决方案&#xff0c;作者蔡司工业质量 在考古环境中&#xff0c;三维扫描技术应用广泛&#xff0c;如存档、保存、复制和分享&#xff08;包括实体和虚拟形式&#xff09;。 文中&#xff0c;通过真实的扫描案例&#xff0c;您将了解到三维光学解决方案…

实战-任意文件下载

实战-任意文件下载 1、开局 开局一个弱口令&#xff0c;正常来讲我们一般是弱口令或者sql&#xff0c;或者未授权 那么这次运气比较好&#xff0c;直接弱口令进去了 直接访问看看有没有功能点&#xff0c;正常做测试我们一定要先找功能点 发现一个文件上传点&#xff0c;不…

022_matrix_dancing_in_Matlab中求解一个超简单的矩阵问题

矩阵体操 首先&#xff0c;可以复习一下向量、矩阵和索引的基础知识。 向量约定矩阵约定矩阵索引 一般而言&#xff0c;我们利用进行计算大概就是以下的步骤&#xff1a; #mermaid-svg-UovF0Uldf5XxntJi {font-family:"trebuchet ms",verdana,arial,sans-serif;fo…

Webserver(2)GCC

目录 安装GCCVScode远程连接到虚拟机编写代码gcc编译过程gcc与g的区别Xftp连接虚拟机上传文件 安装GCC sudo apt install gcc g查看版本是7.5 touch test.c创建代码 但是在虚拟机中写代码很不方便 VScode远程连接到虚拟机编写代码 gcc test.c -o app在虚拟机中用gcc编译的…

世界肺癌日:新药涌现:不断拓展治疗边界

肺癌&#xff0c;这一全球性的健康杀手&#xff0c;每分钟都无情地夺去超过三人的生命&#xff0c;每年导致约180万人不幸离世&#xff0c;占据了全球癌症死亡人数的18%&#xff0c;成为癌症死亡的首要原因。患者不仅要承受生理上的巨大痛苦&#xff0c;还要面对心理上的沉重压…

OpenCV高级图形用户界面(20)更改窗口的标题函数setWindowTitle()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在OpenCV中&#xff0c;cv::setWindowTitle函数用于更改窗口的标题。这使得您可以在程序运行时动态地更改窗口的标题文本。 函数原型 void cv::…

外包干了2年,技术原地踏步。。。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;19年通过校招进入南京某软件公司&#xff0c;干了接近2年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了2年的功能测试&…

一文掌握Kubernates核心组件,构建智能容器管理集群

1.Kubernates简要概述 Kubernates&#xff08;常称为K8s&#xff0c;因省略了“ubernate”中的8个字符&#xff09;是Google开源的容器编排平台&#xff0c;专为简化和自动化应用服务的部署、扩展和管理而设计。它将应用与底层的服务器抽象开来&#xff0c;提供了自动化的机制…

修改huggingface的缓存目录以及镜像源

执行以下语句查看当前配置 huggingface-cli env默认输出应该如下 (py39-transformers) PS D:\py_project\transformers_demo> huggingface-cli envCopy-and-paste the text below in your GitHub issue.- huggingface_hub version: 0.26.1 - Platform: Windows-10-10.0.22…

LeetCode课程表打卡(拓扑排序例题)

例题一&#xff1a;LeetCode &#xff1a;207 你这个学期必须选修 numCourses 门课程&#xff0c;记为 0 到 numCourses - 1 。 在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出&#xff0c;其中 prerequisites[i] [ai, bi] &#xff0c;表示如果要学…

算法速刷(LeetCode)(160.相交链表)

个人思路&#xff1a; 笨蛋做法&#xff0c;但是好用 代码如下 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) {* val x;* next null;* }* }*/ public class Solution …

微信小程序文字转语音播报案例

插件申请 在小程序官方申请同声传译插件&#xff0c;地址&#xff1a; mp.weixin.qq.com 引入插件 在app.json中加入 "plugins": {"WechatSI": {"version": "0.3.6","provider": "wx069ba97219f66d99"}},封装…

Vue入门示例

今天滴学习目标&#xff01;&#xff01;&#xff01; 示例简介HTML内容主体区域输入框列表区域统计和清空 JS引入Vue.js库定义Vue实例el选项data选项methods选项 示例简介 HTML内容 本次实例讲解的是v-for、v-on、v-model来写这小小的实例&#xff0c;下面是实例的效果图&am…

springboot小区物业报修管理系统-计算机设计毕业源码03418

摘 要 本课题的研究对象是小区物业报修管理系统app的设计与实现&#xff0c;该系统实现了用户管理、业主信息管理、报修信息管理、维修记录管理、通知公告管理等功能。本系统在设计上&#xff0c;考虑到系统内容以及系统的受众群体&#xff0c;在系统的美工方面采用了比较正规的…

【JavaEE】【多线程】单例模式

目录 一、设计模式1.1 单例模式1.1.1 饿汉模式1.1.2 懒汉模式 1.2 线程安全问题1.3 懒汉模式线程安全问题的解决方法1.3.1 原子性问题解决1.3.2 解决效率问题1.3.3 解决内存可见性问题和指令重排序问题 一、设计模式 在讲解案例前&#xff0c;先介绍一个概念设计模式&#xff…