Vue基础

Vue基础

image-20250220182539746

1、Vue的基本原理

Vue是一款用于构建用户界面的 JavaScript 框架。采用的MVVM架构(Model-View-ViewModel),通过数据驱动组件化开发来构建用户界面。

MVVM架构

Model,数据层,存储应用的状态数据

View,视图层,即DOM,展示数据的UI

VIewModel,视图模型,Vue实例充当ViewModel,负责把View和Model绑定,实现数据的双向绑定,这样数据变化的时候,自动更新视图。视图更新输入,数据也更新。

响应式系统

这是Vue的核心,通过观察数据的变换,自动更新视图。

Vue 2.x 的实现原理:

1、 初始化响应式数据:Vue实例化时,它会遍历data对象的每个属性,并使用Object.defineProperty为每个属性添加gettersetter

2、依赖收集:当组件的模版里使用某个数据属性,例如{{name}},Vue会通过getter读取该属性。在读取属性时,Vue会将当前的视图与该属性关联,这个过程称为依赖收集。

3、触发更新:当数据属性被修改,setter会触发,并通知所有依赖该属性的视图进行更新。

Vue 3.x 的改进:

使用了ES6的proxy API 来实现响应式系统。优势在于可以拦截更多操作。

当访问响应式对象的属性时,Proxyget 操作会触发依赖收集。

当修改响应式对象的属性时,Proxyset 操作会触发更新。

Proxy 可以拦截对象的所有操作,包括新增属性、删除属性、数组操作等,而 Object.defineProperty 无法监听这些操作。

模版编译

Vue的模板语法(HTML模板)是一种声明式语法,用于描述组件的结构和行为。

在Vue应用运行之前,这些模板会被编译器(Vue Complier)转换成渲染函数

模版编译的过程:

1、解析模版:Vue编译器解析模版字符串,将其转换为一个抽象语法树(AST)。

2、优化AST:对AST抽象语法树进行优化,例如标记静态节点(不随数据变化的节点),以便在后续的渲染过程中减少不必要的操作。

3、生成渲染函数:将优化后的AST转换为一个JavaScript渲染函数。

渲染函数

纯函数,接受组件的上下文_ctx作为参数,返回一个虚拟DOM树。当数据变化时,Vue会重新调用渲染函数,生成新的虚拟DOM树。

虚拟DOM

数据变化时,Vue的响应式系统会触发渲染函数重新执行,生成新的虚拟DOM树。然后,Vue的渲染器Render会比较新旧虚拟DOM树,使用 Diff 算法找出差异,将差异应用到真实DOM上。

组件化

Vue是基于组件开发的,每个组件都是一个独立的Vue实例,有自己的模版、数据、逻辑、样式。组件之间可以嵌套、组合,实现复杂的分层和模块化管理。

特点:

  • 封装性
  • 可复用性
  • 可维护性
  • 声明式语法

组件通信

父传子:子用props接收

子传父: $emit 触发自定义事件

兄弟通信:事件总线(Event Bus), EventBus.$emitEventBus.$on

跨层级通信:provideinject

全局状态管理:Vuex Store

生命周期

Vue的生命周期阶段:

1、创建阶段(组件实例被创建,数据初始化)

  • **beforeCreate**:在实例初始化之后被调用,此时实例的数据(data)和事件还未初始化。
  • **created**:在实例的数据和事件初始化之后被调用,此时可以访问 data 和 methods。

2、挂载阶段(组件被插入到 DOM 中)

  • **beforeMount**:在组件挂载之前被调用,此时模板已编译,但尚未插入到 DOM 中。
  • **mounted**:在组件挂载到 DOM 之后被调用,此时可以访问 DOM 元素。

3、更新阶段(组件的数据或状态发生变化,导致组件重新渲染)

  • **beforeUpdate**:在组件数据更新之前被调用,此时可以访问旧的 DOM 和数据。
  • **updated**:在组件数据更新并重新渲染之后被调用,此时可以访问新的 DOM。

4、销毁阶段(组件被销毁,从 DOM 中移除)

  • **beforeDestroy**(Vue 2.x)/ **beforeUnmount**(Vue 3.x):在组件销毁之前被调用,此时可以访问组件的所有数据和方法。
  • **destroyed**(Vue 2.x)/ **unmounted**(Vue 3.x):在组件销毁之后被调用,此时组件已经从 DOM 中移除。

2、computed 和 watch 的区别

两种不同的响应式机制,用来处理数据变化时的逻辑。

所有响应式数据都会经过劫持,即Vue会给每个属性设置getter和setter(Vue2使用Object.defineProperty,Vue3使用Proxy),以便在数据读取时收集依赖(订阅者),在数据修改时通知这些依赖进行更新。

Watcher:Vue内部会为需要响应式更新的操作创建Watcher对象,负责在依赖的数据变化时触发回调(例如重新渲染视图、重新计算computed等)

computed(计算属性)

基于响应式数据动态派生的值,具有缓存机制,只有当依赖项发生变化时才会重新计算。

1
2
3
4
5
6
7
computed: {
// 当 firstName 或 lastName 变化时,这个 computed watcher会重新求值
fullName() {
console.log('计算 fullName');
return `${this.firstName} ${this.lastName}`;
}
},

Vue实例初始化时,会遍历computed选项,对每个计算属性创建一个Watcher实例,在模版或者代码中访问计算属性时,会调用其getter。如果 computed watcher 被标记为dirty,则调用getter重新计算值,并缓存结果。如果没有变化,则直接返回缓存值。当依赖的数据变化时,对应的 getter 中调用的响应式数据触发 setter,进而通知相关的 Watcher,将其 dirty 标记为 true

watch(侦听器)

用于监听响应式数据的变化,并在数据变化时执行特定的逻辑。当被监听的数据发生变化时,watch 中定义的回调函数会被触发。

1
2
3
4
5
6
7
watch: {
// 当 query 发生变化时,调用 fetchData 函数(可以是异步操作)
query(newVal, oldVal) {
console.log(`query 从 ${oldVal} 变为 ${newVal}`);
this.fetchData(newVal);
}
},

定义一个watch属性时,Vue会为它创建一个普通的Watcher,这个 watcher 会在数据变化时(即 getter 求值时检测到新旧值不同)调用指定的回调函数,并传入新值和旧值。

主要区别

image-20250219222115148

使用配置对象

handler:当被监视的源发生变化时,执行的回调函数,接收新值、旧值作为参数。

immdiate:指示是否在 watcher 初始化后立即调用一次回调

deep:指定是否对对象或数组进行深度侦听,从而捕捉到所有嵌套属性的变化

flush(Vue 3):控制 watcher 回调的执行时机,可选 “pre”(更新前)、”post”(更新后)或 “sync”(同步执行)

3、methods

methods

用于定义组件的方法。它们可以在模板中通过事件绑定或表达式调用,也可以在组件内部直接调用。与data或者computed不同,这些方法不会被Vue自动进行响应式处理、缓存或依赖收集。

1
2
3
4
5
6
7
methods: {
// 定义一个方法,用于反转消息
reverseMessage() {
// 这里的 this 指向 Vue 实例,可以访问 data 中的 message 属性
this.message = this.message.split('').reverse().join('');
}
}

创建Vue实例时,Vue会遍历配置对象中的methods,并把每个方法挂载到Vue实例上。可以通过this.methodName调用方法,也可以用事件绑定@click="methodName"的形式调用方法。

所有在methods中定义的函数上下文(this)绑定到实例上。这样方法内部的this就都指向Vue实例,从而可以访问datacomputedprops等属性。

4、slot

slot是一种内容分发机制(内容插槽机制),用于在组件内部预留“占位符”,让父组件能够将内容插入到子组件预留的位置,从而实现内容的分发和复用。

解决的问题
组件封装的同时仍然允许外部传入 HTML 或其他组件,使得组件既能保持内部逻辑封装,又能灵活地展示外部内容。

插槽的类型

  • 默认插槽:父组件没有给子组件提供具名插槽内容时,默认插槽会渲染默认内容,或者渲染父组件传入的内容。

    1
    <slot>默认主体内容</slot>
  • 具名插槽:通过 name 属性指定插槽名称。

    1
    <slot name="header">默认头部内容</slot>

    父组件要使用 template 标签,并通过 v-slot 指令(或简写 #)指定插槽名称:

    1
    2
    3
    <template v-slot:header>
    <h1>这是自定义头部</h1>
    </template>
  • 作用域插槽:作用域插槽允许子组件向父组件传递数据。

    1
    2
    // 子
    <slot :user="user">默认内容</slot>
    1
    2
    3
    4
    // 父 
    <template v-slot:default="slotProps">
    <p>接收到的内容:{{ slotProps.content }}</p>
    </template>

5、filters过滤器

是一种用于格式化数据的工具,用于在模板中对数据进行格式化。例如格式化日期、货币、字符串大小写转换等。它们可以被定义为全局过滤器或局部过滤器,在模板中通过管道符号(|)使用。

过滤器是 Vue 2.x 中的一个特性,但在 Vue 3.x 中已被移除。

过滤器是一个函数,接收原始数据作为输入,并返回格式化后的数据。

局部过滤器:

1
2
3
4
5
6
filters: {
capitalize(value) {
if (!value) return '';
return value.charAt(0).toUpperCase() + value.slice(1);
}
}

全局过滤器:

1
2
3
4
Vue.filter('capitalize', function (value) {
if (!value) return '';
return value.charAt(0).toUpperCase() + value.slice(1);
});

在模板中使用过滤器

1
<p>{{ message | capitalize }}</p>

6、如何保存页面的当前的状态

页面状态是指页面在某一时刻的所有数据和配置信息的集合。

可能包括:
用户输入:如表单字段的内容。
显示内容:如列表数据、文本内容等。
加载状态:如是否正在加载数据、加载进度等。
UI 状态:如是否显示某个弹窗、是否折叠某个面板等。
路由信息:如当前页面的 URL、路由参数等。

为什么要保存

1、用户体验:当用户离开页面后再次返回时,页面能够恢复到用户离开时的状态,避免用户重新操作。

2、数据持久化:将页面状态保存到本地存储(如 localStoragesessionStorage),以便在页面刷新或关闭后仍能恢复。

3、跨页面共享:将页面状态传递给其他页面或组件,实现数据共享。

方法

1、使用浏览器存储(localStorage / sessionStorage)

localStorage:数据会一直保存,即使浏览器关闭也不丢失,除非主动清除。

sessionStorage:数据在当前会话(tab 或 window)中保存,关闭页面或浏览器后数据会丢失。

数据以键值对的形式存储,通常以字符串格式保存(需要用 JSON.stringify/JSON.parse 进行转换)。

1
2
3
4
5
// 存储到 localStorage 中
localStorage.setItem('pageState', JSON.stringify(state));

// 读取状态(通常在页面加载时执行)
const savedState = JSON.parse(localStorage.getItem('pageState') || '{}');

2、使用 URL 参数或 Hash

将页面状态编码在 URL 的查询字符串或哈希值中。用户在刷新或分享 URL 时,状态可以通过解析 URL 得到。

1
2
3
4
5
6
7
8
9
10
// 保存状态到 URL 查询参数中
const pageState = { currentPage: 3, filter: 'active' };
const queryString = new URLSearchParams(pageState).toString();
window.history.replaceState(null, '', '?' + queryString);

// 读取 URL 参数恢复状态
const params = new URLSearchParams(window.location.search);
const currentPage = params.get('currentPage');
const filter = params.get('filter');
console.log(currentPage, filter);

3、 利用 History API 的 State 对象

TML5 提供了 History API(如 history.pushStatehistory.replaceState),可以将状态对象与历史记录关联。当用户使用浏览器的前进后退按钮时,可以通过 history.state 获取之前保存的状态。

1
2
3
4
5
6
7
8
9
10
// 保存状态到当前历史记录中
const state = { tab: 'profile', scrollTop: window.pageYOffset };
history.replaceState(state, '', window.location.href);

// 读取历史记录中的状态
const savedState = history.state;
if (savedState) {
console.log('当前激活的 tab:', savedState.tab);
window.scrollTo(0, savedState.scrollTop);
}

4、 在 Vue 应用中的状态管理

Vuex:集中存储应用的所有状态,通过 mutations 和 actions 修改状态,并且可以利用插件(如 vuex-persistedstate)将状态持久化到 localStorage。

Pinia:Vue 3 推荐的状态管理库,具有类似 Vuex 的特性,也支持状态持久化。

1、安装插件

2、在VueX store中配置

3、在组件中使用

7、常见的事件修饰符及其作用

事件修饰符,是一种语法糖,用于在模板中对事件处理器进行预处理,从而实现简单的事件行为操作。

  • .stop:调用event.stopPropagation(),阻止事件向父级元素冒泡。点击事件只在当前元素上触发,不再传递给父组件或父元素时使用。

    1
    <button @click.stop="handleClick">点击我</button>
  • .prevent:调用 event.preventDefault(),阻止事件的默认行为(如提交表单、链接跳转)。

    1
    2
    3
    4
    <form @submit.prevent="handleSubmit">
    <input type="text">
    <button type="submit">提交</button>
    </form>
  • .stop.prevent:同时阻止事件冒泡和默认行为,可以连写。

1
<a href="https://example.com" @click.stop.prevent="handleLinkClick">点击链接</a>
  • .capture:在事件捕获阶段触发事件处理器,而不是等待事件冒泡到目标元素时使用。

    1
    2
    3
    <div @click.capture="handleCapture">
    <button @click="handleButtonClick">点击按钮</button>
    </div>
  • .self:只有事件的目标(event.target)是绑定事件的元素本身时才触发处理器。

    1
    2
    3
    4
    5
    <!-- 只有点击 div 自身才触发 -->
    <div @click.self="handleSelfClick" style="padding: 20px; border: 1px solid #ccc;">
    <button>点击我不会触发 div 的事件</button>
    <p>点击空白区域才触发 div 的事件</p>
    </div>
  • .once:事件处理器只触发一次,触发后自动解绑。

    1
    <button @click.once="handleOnce">只点击一次有效</button>
  • .passive(vue3):告诉浏览器,这个事件监听器不会调用 event.preventDefault()。监听器是“被动”的(passive),浏览器可以放心地继续执行默认操作(如页面滚动)。

    1
    2
    3
    4
    <div @touchmove.passive="handleTouchMove" style="height: 200px; overflow: scroll;">
    <!-- 内容很多的区域 -->
    <p v-for="i in 50" :key="i">{{ i }}</p>
    </div>
  • .native:用于自定义组件上,想监听该组件根元素的原生 DOM 事件时使用。

    区分自定义事件和原生事件
    创建一个自定义组件时,可以在组件内部通过 $emit('click') 发出一个事件。父组件如果写 <my-component @click="handler">,默认是监听这个自定义事件,而不是组件根元素的 DOM 事件。

    使用 .native 修饰符时,Vue 会将事件监听器直接绑定到自定义组件的根 DOM 元素上(即组件模板的最外层元素),从而捕获该 DOM 元素上触发的原生事件。

    在 Vue 3.x 中,.native 修饰符已被移除,Vue 3 提供了更灵活的事件监听机制,可以直接在自定义组件上监听原生事件。Vue 3 会自动将 @click 绑定到 <CustomButton> 的根元素上,无需 .native 修饰符。

8、v-if、v-show、v-html 指令的原理

1、v-if:决定是否在DOM中创建、销毁元素。

当条件为 true 时,Vue 会生成该元素的虚拟 DOM,并挂载到真实 DOM 上。

当条件为 false 时,该元素及其子节点完全不会出现在 DOM 中,也不会占用任何内存。

使用场景:切换频率低、大量DOM节点。使用 v-if 可以避免不必要的渲染开销。但由于每次切换都需要重新创建或销毁 DOM,所以切换频繁时性能可能不如 v-show。

2、v-show:基于 CSS 的显示隐藏。

无论条件是否为 true,都始终会在 DOM 中渲染该元素。只是通过修改元素的 CSS 属性(display)来控制元素的可见性。相当于display 属性被设置为 none

3、v-html:将一个字符串解析为 HTML,然后插入到元素内部。

会将绑定的字符串直接设置为元素的 innerHTML,从而渲染出相应的 HTML 内容。

9、 v-model 是如何实现的

v-model实现了数据的双向绑定。

语法糖:在表单模板中写 <input v-model="message"> 实际上是 Vue 内部自动转换成类似下面的代码:

1
<input :value="message" @input="message = $event.target.value">

父组件使用 v-model:本质通过prop和$.emit实现。在自定义组件上使用 v-model 时,Vue 会默认将其绑定到组件的 value prop 上,并监听组件发出的 input 事件。

10、data为什么是一个函数而不是对象

让每个组件都有自己独立的数据副本,而不是共享一个对象,有利于组件的复用!

组件数据隔离
data 定义为函数可以确保每个组件实例拥有独立的数据副本,避免状态共享带来的副作用。‘

根实例特殊性
由于根实例只有一个,所以可以将 data 定义为对象;但组件(可复用、多实例)必须使用函数返回数据对象。

1
2
3
4
5
data() {
return {
count: 0
};
},

11、对keep-alive的理解

包装器组件,不渲染实际的DOM元素,而是作为一个抽象组件,通过内部机制缓存子组件的实例状态。

缓存动态组件的实例,避免反复创建与销毁。

<keep-alive> 内部会维护一个缓存对象,当子组件第一次渲染时,会把其 VNode 存储起来;当切换到其他组件时,被缓存的组件不会调用销毁钩子(如 beforeDestroydestroyed),而是调用 deactivated 钩子;当组件再次激活时,则调用 activated 钩子。

activated:当组件被激活(即从缓存中恢复显示)时调用。

deactivated:当组件被停用(即离开视图,但缓存保留)时调用。

通过 includeexclude 属性精确控制哪些组名称需要缓存。

1
2
3
4
5
6
7
8
// :is 属性用于动态绑定组件的名称或对象
<keep-alive include="Home,About">
<component :is="view"></component>
</keep-alive>

<keep-alive exclude="Login">
<component :is="view"></component>
</keep-alive>

12、$nextTick 原理及作用

修改了响应式数据后,数据更新后,DOM 可能还没有完成更新。

$nextTick 允许在 DOM 更新完成后执行回调函数。确保在回调函数执行时,DOM 已经完成了所有由当前数据变化引起的更新。

1
2
3
4
5
// DOM 更新并不是立即完成的
// 使用 $nextTick 来确保在 DOM 更新后执行操作
this.$nextTick(() => {
console.log(this.$refs.text.textContent); // 此时会输出最新的文本内容
});

13、给 data 中的对象属性添加一个新的属性

Vue 2 采用 Object.defineProperty 对已存在的属性进行响应式处理,而无法检测后续新增的属性。自然就不会触发视图的更新。

使用Vue.setthis.$set

1
2
3
// 使用 $set 方法添加新属性 b,并赋值 2
this.$set(this.myObject, 'b', 2);
// 或者使用 Vue.set(this.myObject, 'b', 2);

在 Vue 3 中,由于采用了 ES6 的 Proxy 实现响应式,所以直接添加新属性也能被拦截,从而实现响应式更新,因此这个问题在 Vue 3 中不存在。

14、Vue封装数组的方法

为了实现数组的响应式更新,Vue对数组的方法进行封装或者重写,确保调用他它们的时候能通知依赖更新,让视图随着数组的变化得到更新。调用方法时,Vue会在执行原有逻辑的同时触发依赖收集器的通知,让所有依赖该数组的watcher得到更新,从而重新渲染视图。

  • push:向数组末尾添加一个或多个元素。
  • pop:从数组末尾移除最后一个元素。
  • shift:从数组头部移除第一个元素。
  • unshift:向数组头部添加一个或多个元素。
  • splice:在数组的指定位置添加或删除元素。
  • sort:对数组进行排序。
  • reverse:反转数组中元素的顺序。

使用索引修改数组元素,不会被响应式系统检测到。需要使用set。

Vue.set(this.items, index, newValue)this.$set(this.items, index, newValue)

在 Vue 3 中,由于采用了 ES6 的 Proxy 实现响应式,所以可以直接检测数组的新增、修改等操作,无需像 Vue 2 那样重写数组方法。

15、Vue 单页应用与多页应用的区别

单页应用SPA:通常只有一个HTML文件,整个应用在首次加载时通过JS加载所有必要资源(HTML,CSS,JS,图片等)。使用Vue Router路由库在客户端进行路由管理,根据URI变化加载不同的组件或者视图,无需刷新整个页面。根据用户操作动态切换视图,所有页面切换都在当前页面完成,不会触发页面重新加载。整个应用由一个根实例管理,数据状态可以在各个组件之间共享和传递。

多页应用MPA:每个页面都有独立的HTML文件,页面切换依赖服务器加载不同的页面。页面导航也是由服务器处理,每次跳转要完整刷新页面,每个页面都是相对独立的应用,数据状态不会跨页面共享,依赖后端管理或者浏览器存储。

16、Vue自定义指令

指令:带有v-前缀的特殊属性,用来操作DOM的(条件渲染v-if、绑定-bind等)

自定义指令:封装DOM操作逻辑

定义对象时,可以包含多个钩子函数:

Vue 2 自定义指令的钩子名称:

bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性初始化设置,但此时还没有插入 DOM。

inserted:被绑定元素插入到 DOM 时调用,此时可以操作 DOM。

update:所在组件的 VNode 更新时调用,但可能发生在子节点更新之前。

componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。

unbind:只调用一次,指令与元素解绑时调用,用于清理工作。

Vue 3 自定义指令的钩子名称一般为:

  • created:指令第一次绑定到元素时调用,且在挂载前调用。
  • beforeMount:在元素插入 DOM 前调用。
  • mounted:在元素插入 DOM 后调用(通常用来操作 DOM)。
  • beforeUpdate:在组件更新前调用。
  • updated:在组件更新后调用。
  • beforeUnmount:在指令解绑前调用。
  • unmounted:在指令解绑后调用。

17、子组件可以直接改变父组件的数据吗

在 Vue 中,子组件不能直接修改父组件的数据,因为父组件通过 props 向子组件传递的数据是只读的。

父组件向子组件传递数据时,子组件通过 props 接收。Vue 将这些 props 设置为只读属性,目的是防止子组件直接修改父组件的数据,以保持数据流向的清晰和可预测。

如果子组件需要改变父组件的数据,应该通过触发事件(例如使用 this.$emit)来通知父组件,由父组件在接收到事件后进行数据修改。这样既遵循了单向数据流,也保持了组件间的解耦。

18、 Vue是如何收集依赖的

每个data属性在初始化时会被遍历,被Object.defineProperty劫持,给每个属性添加getter和setter。这样读取属性时会执行getter,修改属性时,会执行setter。

Dep依赖管理器:每个响应式属性都有一个关联的Dep对象,负责维护依赖列表,保存所有依赖的引用。

Watcher:每个组件渲染过程都会创建一个Watcher,代表了组件的渲染函数。渲染的时候,Watcher会访问data中的响应式属性,从而触发这些属性的getter。

依赖收集的流程

1、设置Watcher:组件渲染时,把当前watcher赋值给全局的Dep.target。

2、读取数据,触发getter:渲染过程中,在模板读取data中的属性时,调用该属性的getter。getter内部会调用Dep.depend。

3、注册依赖:depend方法检查当前有没有Dep.target,有就把Watcher添加到当前属性对应的Dep中,Watcher也会把这个Dep收集起来。

4、数据更新通知:数据变化时,setter被调用,通知对应的Dep对象。然后Dep会遍历所有订阅的watcher,触发它们的更新,进而重新渲染组件或者重新计算计算属性。

19、assets和static的区别

两个都是存放静态资源文件。项目中所需要的资源文件图片,字体图标,样式文件等都可以放在这两个文件下。

如果资源需要在组件中动态引用、参与模块化打包、优化、缓存控制,建议放在 assets 文件夹中。

如果资源不需要经过打包处理,且希望保持原始文件名和内容(例如外部库、静态 HTML、favicon 等),则放在 static/public 文件夹中。

20、Vue如何做性能优化

1、异步批量更新

利用 this.$nextTick() 确保在 DOM 更新后执行依赖最新 DOM 状态的逻辑。

2、合理使用计算属性

将复杂的衍生数据计算封装为 computed 属性,而不是放在 methods 中每次调用时重新计算。计算属性具有缓存特性,只在依赖数据发生变化时重新计算,避免重复计算。

3、合理选择 v-if 与 v-show

v-if:适用于不频繁切换的场景,因为每次切换会创建或销毁 DOM。

v-show:适用于频繁切换的场景,因为它只改变 CSS 的 display 属性,不会销毁 DOM。

4、使用 keep-alive 缓存组件

<keep-alive> 会缓存被包裹的动态组件实例,避免重复创建,保留组件状态。

5、动态 import & 路由懒加载

在路由配置中使用动态 import,减少初始加载文件大小,按需加载,提升首屏加载速度。

1
const Home = () => import('./components/Home.vue');

6、Tree Shaking:利用 webpack 移除未使用的代码,减小打包文件体积。

7、图片与静态资源优化:使用合适的 Loader 对图片、字体等资源进行压缩、优化,生成带 hash 值的文件名以利于缓存。将无需处理的静态资源放在 public 文件夹中,直接复制到输出目录,减少构建时间。

8、全局状态管理:使用 Vuex 或 Pinia 集中管理状态,避免不必要的组件间数据传递和重复渲染。

9、服务端渲染(SSR):对于需要 SEO 和快速首屏加载的应用,可以使用 Nuxt.js 等解决方案进行服务端渲染,将初始内容在服务器端生成并发送给浏览器。