链接预取
Nuxt 提供多种资源预加载策略,让页面切换几乎瞬间完成。预取的核心思想是:在用户需要之前就提前加载资源。
预取策略一览
| 策略 | 触发时机 | 加载内容 | 适用场景 |
|---|---|---|---|
| NuxtLink 预取 | 链接进入视口 | 页面 JS/CSS | 默认开启,通用 |
| 悬停预取 | 鼠标悬停 | 页面组件 | 导航菜单 |
preloadRouteComponents | 手动调用 | 页面组件 | 特定页面 |
<link rel="preload"> | 页面加载时 | 关键资源 | 首屏字体、图片 |
<link rel="prefetch"> | 页面加载后 | 下一页资源 | 即将访问的页面 |
<link rel="preconnect"> | 页面加载时 | 建立 TCP 连接 | 第三方 API |
预取 vs 预加载 vs 预连接
- 预取(prefetch):低优先级,空闲时加载
- 预加载(preload):高优先级,立即加载
- 预连接(preconnect):提前建立网络连接
NuxtLink 预取
<NuxtLink> 默认会在链接进入视口时预取目标页面的代码和数据:
vue
<template>
<!-- 默认:进入视口时预取 -->
<NuxtLink to="/about">关于</NuxtLink>
<!-- 禁用预取(大体积页面或移动端) -->
<NuxtLink to="/heavy-page" no-prefetch>重页面</NuxtLink>
<!-- 显式启用 -->
<NuxtLink to="/about" :prefetch="true">关于</NuxtLink>
</template>预取行为详解
- 用户滚动页面,
<NuxtLink>进入视口 - Nuxt 在后台加载目标页面的 JS、CSS 和数据
- 用户点击链接时,页面几乎瞬间切换(资源已就绪)
预取的智能之处
- 只预取视口内的链接(不会一次预取所有链接)
- 使用
requestIdleCallback在浏览器空闲时预取 - 预取的 JS 代码可以和其他资源并行下载
INFO
️ 何时禁用预取
- 页面体积很大(如包含大量图表)
- 移动端网络有限
- 页面依赖大量动态数据
全局配置
ts
export default defineNuxtConfig({
router: {
options: {
prefetch: true, // 默认 true,全局启用预取
// prefetch: false, // 全局禁用(不推荐)
},
},
})preloadRouteComponents
手动预加载指定路由的组件,适合在特定时机触发:
ts
// 预加载特定路由
preloadRouteComponents('/dashboard')
// 在鼠标悬停时预加载
function handleMouseEnter() {
preloadRouteComponents('/dashboard')
}典型场景——登录后预加载仪表盘
ts
async function handleLogin() {
const success = await login(credentials)
if (success) {
// 登录成功后,预加载仪表盘
preloadRouteComponents('/dashboard')
await navigateTo('/dashboard')
}
}典型场景——导航菜单悬停预加载
vue
<template>
<nav>
<NuxtLink
v-for="item in menuItems"
:key="item.path"
:to="item.path"
@mouseenter="preloadRouteComponents(item.path)"
>
{{ item.label }}
</NuxtLink>
</nav>
</template>preloadRouteComponents vs NuxtLink 预取
preloadRouteComponents:手动触发,更精确控制- NuxtLink 预取:自动触发,基于视口
- 两者可以配合使用
prefetchComponents
预取组件(在后台加载但不立即渲染),适合预加载大型组件:
ts
// 预取单个组件
prefetchComponents('MyHeavyChart')
// 预取多个组件
prefetchComponents(['ChartComponent', 'MapComponent', 'EditorComponent'])prefetchComponents vs preloadRouteComponents
prefetchComponents:预取组件代码preloadRouteComponents:预取路由对应的所有资源(组件 + 数据)
prefetchComponents 适合
组件很大但不确定用户是否会访问对应页面。
资源预加载
preload —— 高优先级预加载
当前页面马上需要的关键资源,浏览器会立即下载:
ts
useHead({
link: [
// 预加载关键字体
{ rel: 'preload', href: '/fonts/inter.woff2', as: 'font', type: 'font/woff2', crossorigin: '' },
// 预加载首屏图片
{ rel: 'preload', href: '/images/hero.jpg', as: 'image' },
// 预加载关键 CSS
{ rel: 'preload', href: '/css/critical.css', as: 'style' },
],
})preload 的 as 属性
| 值 | 资源类型 | 优先级 |
|---|---|---|
font | 字体文件 | 高 |
image | 图片 | 中 |
style | CSS | 高 |
script | JavaScript | 高 |
fetch | API 数据 | 中 |
prefetch —— 低优先级预取
下一页面可能需要的资源,浏览器在空闲时下载:
ts
useHead({
link: [
// 预取下一页面的 JS
{ rel: 'prefetch', href: '/js/dashboard.js' },
// 预取下一页面的图片
{ rel: 'prefetch', href: '/images/next-page-hero.jpg' },
],
})preconnect —— 提前建立连接
提前建立 TCP/TLS 连接,减少首次请求的延迟:
ts
useHead({
link: [
// 预连接 API 服务器
{ rel: 'preconnect', href: 'https://api.example.com' },
// 仅预解析 DNS(更轻量)
{ rel: 'dns-prefetch', href: 'https://cdn.example.com' },
],
})| 类型 | 行为 | 何时用 |
|---|---|---|
preconnect | DNS + TCP + TLS 完整连接 | 即将请求的域名 |
dns-prefetch | 仅 DNS 查询 | 可能请求的域名 |
预连接的时机很重要
- 过早预连接(如页面还没加载完)会浪费连接资源
- 推荐只对 2-3 个关键域名预连接
- 对可能用到的域名用
dns-prefetch(更轻量)
预取策略选择
根据页面类型选择
| 页面类型 | 推荐策略 | 原因 |
|---|---|---|
| 首页 | NuxtLink 预取 + preconnect | 默认即可 |
| 文章列表 | NuxtLink 预取 | 列表中的链接自动预取 |
| 文章详情 | 预加载首屏图 + 预取评论 | 关键资源优先 |
| 管理后台 | 禁用预取 | 体积大、移动端不友好 |
| 登录页 | 悬停预取仪表盘 | 登录后跳转更快 |
根据网络条件选择
ts
// 检测网络条件,动态决定是否预取
const connection = useNavigatorConnection()
if (connection.value?.saveData || connection.value?.effectiveType === '2g') {
// 低速网络或用户开启了省流模式:禁用预取
// ...
}性能注意事项
- 不要过度预取:预取太多会浪费带宽和内存
- 移动端注意:移动网络下预取可能影响当前页面性能
- 重页面禁用预取:体积大的页面用
no-prefetch - 关键资源用
preload:不是预取,而是高优先级预加载 - 第三方域名用
preconnect:减少首次请求延迟 - 限制预连接数量:最多 2-3 个域名
知识脉络
text
Head 管理 → SEO Meta → Open Graph 与 Twitter → 你在这里:链接预取
│
├─→ 相关:路由与导航 → NuxtLink
│
└─→ 相关:视图与布局 → 页面过渡