1、定义、工作原理、优缺点、适用场景以及特点
| 特性 | MPA (多页应用) | SPA (单页应用) |
|---|---|---|
| 定义 | 由多个独立HTML页面构成的应用,每次页面跳转需要重新加载 | 只有一个HTML页面,通过JavaScript动态重写内容 |
| 工作原理 | • 每次页面跳转触发完整页面刷新 • 服务器根据路由返回不同HTML • 通过超链接进行页面跳转 | • 首次加载下载所有资源 • 前端路由管理不同视图 • AJAX/Fetch API进行数据交互 |
| 优点 | ✅ SEO友好:每个页面有独立URL和内容,搜索引擎直接抓取 ✅ 初始加载性能:只加载当前页面所需资源 ✅ 易于开发:传统开发模式,无需复杂前端路由 ✅ 浏览器兼容性好:基本功能不依赖JavaScript ✅ 易于拆分部署:页面可独立开发和部署 | ✅ 用户体验好:页面切换无刷新,响应迅速 ✅ 前后端分离:前端专注UI,后端专注API ✅ 组件化开发:组件复用,开发效率高 ✅ 减轻服务器压力:服务器只需提供API ✅ 状态管理:前端维护应用状态,实现复杂交互 |
| 缺点 | ❌ 页面切换性能差:每次跳转需重新加载整个页面 ❌ 开发效率较低:需重复编写公共部分代码 ❌ 前后端耦合:通常需要后端服务器渲染页面 ❌ 资源重复加载:公共资源可能每个页面都重复加载 | ❌ SEO难度大:内容通过JS动态生成,爬虫抓取困难 ❌ 首次加载慢:需一次性下载所有必需资源 ❌ JavaScript依赖:必须启用JavaScript才能使用 ❌ 浏览器历史管理:需要前端路由库管理历史记录 |
| 适用场景 | • 内容型网站(博客、新闻) • SEO要求极高的项目 • 需要快速上线的简单项目 • 企业官方网站 | • 交互复杂的后台系统 • 需要类原生体验的Web应用 • 移动端Web应用 • 数据密集型应用 |
| 技术栈 | • 传统服务端渲染 • 多HTML文件 • 服务端模板引擎 | • React/Vue/Angular • 前端路由 • 状态管理库 |
| 性能特点 | • 首屏加载快 • 页面切换慢 • 资源按需加载 | • 首屏加载慢 • 页面切换快 • 资源一次性加载 |
1.1 MPA优点
// 1. SEO 友好 - 服务端渲染完整内容
// 搜索引擎可以直接抓取页面内容
server.get('/products', (req, res) => {
const products = getProductsFromDB();
res.render('products', { products }); // 服务端渲染完整HTML
});
// 2. 首屏加载快 - 只加载当前页面资源
<!-- about.html 只包含关于页面的CSS和JS -->
<link rel="stylesheet" href="/css/about.css">
<script src="/js/about.js"></script>
// 3. 技术栈灵活 - 不同页面可用不同技术
// 首页用 React,管理后台用 Vue,博客用传统服务端渲染
// 4. 渐进式增强 - 基础功能不依赖JS
<noscript>
<p>请启用JavaScript获得更好体验</p>
</noscript>
1.2 MPA缺点
// 1. 页面跳转体验差
// 每次跳转都有白屏和资源重载
window.location.href = '/products'; // 完整页面刷新
// 2. 开发效率低
// 重复的头部、底部需要在每个页面维护
<!-- header 在每个HTML文件重复 -->
<header>
<nav>...</nav>
</header>
// 3. 资源利用率低
// 公共库在每个页面重复加载
<script src="/js/jquery.js"></script> <!-- 每个页面都加载 -->
<script src="/js/utils.js"></script> <!-- 每个页面都加载 -->
// 4. 状态管理困难
// 页面间状态传递依赖URL参数或存储
const searchParams = new URLSearchParams(window.location.search);
const userId = searchParams.get('user_id'); // 通过URL传递状态
1.3 SPA优点
// 1. 用户体验流畅
// 使用前端路由实现无刷新跳转
import { createRouter, createWebHistory } from 'vue-router';
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: '/', component: Home },
{ path: '/about', component: About },
{ path: '/products', component: Products }
]
});
// 2. 组件化开发
// 可复用组件提高开发效率
// Button.vue
<template>
<button :class="variant" @click="$emit('click')">
<slot></slot>
</button>
</template>
```
// 3. 前后端分离
// 前端独立开发部署,后端专注API
// api.js
export const api = {
getProducts: () => fetch('/api/products'),
createOrder: (data) => fetch('/api/orders', {
method: 'POST',
body: JSON.stringify(data)
})
};
// 4. 状态管理集中
// 使用 Vuex/Pinia 管理全局状态
// store.js
export const useStore = defineStore('main', {
state: () => ({
user: null,
cart: []
}),
actions: {
async login(credentials) {
this.user = await api.login(credentials);
}
}
});
```
1.4 SPA缺点
// 1. SEO 难度大
// 初始HTML内容为空,依赖JS渲染
<html>
<head>
<title>我的SPA应用</title>
</head>
<body>
<div id="app"></div> <!-- 初始为空 -->
<script src="/js/app.js"></script>
</body>
</html>
// 2. 首屏加载性能
// 首次需要下载所有框架和业务代码
// webpack.config.js - 代码分割优化
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\/]node_modules[\/]/,
name: 'vendors',
chunks: 'all',
}
}
}
}
};
// 3. 内存管理复杂
// 需要手动清理事件监听和定时器
// Vue组件示例
onBeforeUnmount(() => {
clearInterval(timer);
eventBus.off('custom-event', handler);
});
// 4. 浏览器历史管理
// 需要处理路由和浏览器历史记录
router.beforeEach((to, from, next) => {
// 路由守卫逻辑
if (to.meta.requiresAuth && !isAuthenticated) {
next('/login');
} else {
next();
}
});