Skip to content

链接预取

Nuxt 提供多种资源预加载策略,让页面切换几乎瞬间完成。预取的核心思想是:在用户需要之前就提前加载资源

预取策略一览

策略触发时机加载内容适用场景
NuxtLink 预取链接进入视口页面 JS/CSS默认开启,通用
悬停预取鼠标悬停页面组件导航菜单
preloadRouteComponents手动调用页面组件特定页面
<link rel="preload">页面加载时关键资源首屏字体、图片
<link rel="prefetch">页面加载后下一页资源即将访问的页面
<link rel="preconnect">页面加载时建立 TCP 连接第三方 API

预取 vs 预加载 vs 预连接

  • 预取(prefetch):低优先级,空闲时加载
  • 预加载(preload):高优先级,立即加载
  • 预连接(preconnect):提前建立网络连接

<NuxtLink> 默认会在链接进入视口时预取目标页面的代码和数据:

vue
<template>
  <!-- 默认:进入视口时预取 -->
  <NuxtLink to="/about">关于</NuxtLink>

  <!-- 禁用预取(大体积页面或移动端) -->
  <NuxtLink to="/heavy-page" no-prefetch>重页面</NuxtLink>

  <!-- 显式启用 -->
  <NuxtLink to="/about" :prefetch="true">关于</NuxtLink>
</template>

预取行为详解

  1. 用户滚动页面,<NuxtLink> 进入视口
  2. Nuxt 在后台加载目标页面的 JS、CSS 和数据
  3. 用户点击链接时,页面几乎瞬间切换(资源已就绪)

预取的智能之处

  • 只预取视口内的链接(不会一次预取所有链接)
  • 使用 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' },
  ],
})

preloadas 属性

资源类型优先级
font字体文件
image图片
styleCSS
scriptJavaScript
fetchAPI 数据

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' },
  ],
})
类型行为何时用
preconnectDNS + TCP + TLS 完整连接即将请求的域名
dns-prefetch仅 DNS 查询可能请求的域名

预连接的时机很重要

  • 过早预连接(如页面还没加载完)会浪费连接资源
  • 推荐只对 2-3 个关键域名预连接
  • 对可能用到的域名用 dns-prefetch(更轻量)

预取策略选择

根据页面类型选择

页面类型推荐策略原因
首页NuxtLink 预取 + preconnect默认即可
文章列表NuxtLink 预取列表中的链接自动预取
文章详情预加载首屏图 + 预取评论关键资源优先
管理后台禁用预取体积大、移动端不友好
登录页悬停预取仪表盘登录后跳转更快

根据网络条件选择

ts
// 检测网络条件,动态决定是否预取
const connection = useNavigatorConnection()

if (connection.value?.saveData || connection.value?.effectiveType === '2g') {
  // 低速网络或用户开启了省流模式:禁用预取
  // ...
}

性能注意事项

  1. 不要过度预取:预取太多会浪费带宽和内存
  2. 移动端注意:移动网络下预取可能影响当前页面性能
  3. 重页面禁用预取:体积大的页面用 no-prefetch
  4. 关键资源用 preload:不是预取,而是高优先级预加载
  5. 第三方域名用 preconnect:减少首次请求延迟
  6. 限制预连接数量:最多 2-3 个域名

知识脉络

text
Head 管理 → SEO Meta → Open Graph 与 Twitter → 你在这里:链接预取

                                               ├─→ 相关:路由与导航 → NuxtLink

                                               └─→ 相关:视图与布局 → 页面过渡

基于 Nuxt 4 官方文档整理编写