13. 示例 [nuxt-10]:asyncData 及加载中
页面中的 [asyncData] 函数用于异步加载数据(通常为外部数据)。 [nuxt] 会在 [asyncData] 函数执行完毕后才启动页面生命周期。因此,只有在获取到外部数据后,页面才会被渲染。该函数既可在服务器端也可在客户端执行,遵循以下规则:
- 当页面直接向服务器请求时,仅由服务器执行函数 [asyncData];
- 随后在客户端导航时,仅由客户端执行函数 [asyncData];
最终,客户端或服务器中仅有一方会执行该函数。此外,当由客户端执行函数 [asyncData] 时,[nuxt] 会显示一个可配置的进度条。
函数 [asyncData] 可向搜索引擎提供包含数据的页面,从而提升其相关性。
示例 [nuxt-10] 最初是通过复制项目 [nuxt-01] 获得的:

只有 [page1] 页面发生了变化。
13.1. 页面 [page1]
页面 [page1] 的代码如下:
<!-- 视图 1 -->
<template>
<Layout :left="true" :right="true">
<!-- 导航 -->
<Navigation slot="left" />
<!-- 消息-->
<b-alert slot="right" show variant="primary"> Page 1 -- result={{ result }} </b-alert>
</Layout>
</template>
<script>
/* eslint-disable no-console */
/* eslint-disable nuxt/no-timing-in-fetch-data */
import Navigation from '@/components/navigation'
import Layout from '@/components/layout'
export default {
name: 'Page1',
// 使用的组件
components: {
Layout,
Navigation
},
// 异步数据
asyncData(context) {
// 日志
console.log('[page1 asyncData started]')
// 返回一个 Promise
return new Promise(function(resolve, reject) {
// 模拟异步函数
setTimeout(function () {
// 返回异步结果——此处为一个随机数
resolve({ result: Math.floor(Math.random() * Math.floor(100)) })
// 日志
console.log('[page1 asyncData finished]')
}, 5000)
})
},
// 生命周期
beforeCreate() {
console.log('[page1 beforeCreate]')
},
created() {
console.log('[page1 created]')
},
beforeMount() {
console.log('[page1 beforeMount]')
},
mounted() {
console.log('[page1 mounted]')
}
}
</script>
- 第 26-39 行:函数 [asyncData]。我们已经研究过该函数(参见链接段落)。该函数在页面生命周期开始前执行。因此,不能在函数中使用关键字 [this];
- 第30行:该函数必须返回一个[Promise]对象,或使用async/await语法;
- 第32-37行:通过设置5秒的等待时间(第37行)来模拟Promise的异步函数;
- 第34行:异步函数的结果以 {result :...} 对象的形式返回。由函数 [asyncData] 返回的异步对象被整合到页面中的 [data] 对象中。 这就是为什么在模板的第7行中,[result]对象可用,尽管页面并未定义[data]对象;
13.2. [asyncData] 进度条的配置
当页面 [page1] 作为客户端导航的目标(模式 SPA)时, 客户端将执行函数 [asyncData],此时 [nuxt] 会显示进度条,并在函数 [asyncData] 返回结果后将其隐藏。 文件 [nuxt.config.js] 中的属性 [loading] 可用于配置此进度条:
loading: {
color: 'blue',
height: '5px',
throttle: 200,
continuous: true
},
默认情况下,[nuxt] 的加载图片是一个占满页面宽度的进度条。该进度条具有颜色和粗细。彩色线条会从 0% 逐渐增长至 100% 的长度,其增长速度取决于等待时长。
- 第 2 行:设置进度条的颜色;
- 第 3 行:设置进度条的宽度(以像素为单位);
- 第 4 行:[throttle] 表示动画开始前的延迟时间(以毫秒为单位)。这样可以避免在 [asyncData] 函数快速返回结果时出现动画画面;
- 第 5 行:[continuous] 设定进度条动画的行为。默认情况下,进度条会从 0% 逐渐增长到 100% 的大小,具体速度取决于等待时间的长短。 使用 [continuous:true] 时,彩色进度条将以恒定速度从 0% 增长至 100%,然后循环重复,直到 [asyncData] 函数返回结果为止;
13.3. Exécution
启动应用程序,然后手动向服务器请求页面 [page1]:

日志如下:

- 可以看到,只有服务器 [1] 执行了函数 [asyncData],并且是在页面循环之前执行的;
现在让我们查看服务器发送的页面(源代码):
<!doctype html>
<html data-n-head-ssr>
<head>
<title>Introduction à [nuxt.js]</title>
<meta data-n-head="ssr" charset="utf-8">
<meta data-n-head="ssr" name="viewport" content="width=device-width, initial-scale=1">
<meta data-n-head="ssr" data-hid="description" name="description" content="ssr routing loading asyncdata middleware plugins store">
<link data-n-head="ssr" rel="icon" type="image/x-icon" href="/favicon.ico">
<base href="/nuxt-10/">
<link rel="preload" href="/nuxt-10/_nuxt/runtime.js" as="script">
<link rel="preload" href="/nuxt-10/_nuxt/commons.app.js" as="script">
<link rel="preload" href="/nuxt-10/_nuxt/vendors.app.js" as="script">
<link rel="preload" href="/nuxt-10/_nuxt/app.js" as="script">
...
</head>
<body>
<div data-server-rendered="true" id="__nuxt">
<div id="__layout">
<div class="container">
<div class="card">
<div class="card-body">
<div role="alert" aria-live="polite" aria-atomic="true" align="center" class="alert alert-success">
<h4>[nuxt-10] : asyncData et loading</h4>
</div>
<div>
<div class="row">
<div class="col-2">
<ul class="nav flex-column">
<li class="nav-item">
<a href="/nuxt-10/" target="_self" class="nav-link">
Home
</a>
</li>
<li class="nav-item">
<a href="/nuxt-10/page1" target="_self" class="nav-link active nuxt-link-active">
Page 1
</a>
</li>
<li class="nav-item">
<a href="/nuxt-10/page2" target="_self" class="nav-link">
Page 2
</a>
</li>
</ul>
</div> <div class="col-10"><div role="alert" aria-live="polite" aria-atomic="true" class="alert alert-primary"> Page 1 -- result=3 </div></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>window.__NUXT__ = (function (a, b, c) {
return {
layout: "default", data: [{ result: 3 }], error: null, serverRendered: true,
logs: [
{ date: new Date(1574939615256), args: ["[page1 asyncData started]"], type: a, level: b, tag: c },
{ date: new Date(1574939620263), args: ["[page1 asyncData finished]"], type: a, level: b, tag: c },
{ date: new Date(1574939620285), args: ["[page1 beforeCreate]"], type: a, level: b, tag: c },
{ date: new Date(1574939620287), args: ["[page1 created]"], type: a, level: b, tag: c }
]
}
}("log", 2, ""));</script>
<script src="/nuxt-10/_nuxt/runtime.js" defer></script>
<script src="/nuxt-10/_nuxt/commons.app.js" defer></script>
<script src="/nuxt-10/_nuxt/vendors.app.js" defer></script>
<script src="/nuxt-10/_nuxt/app.js" defer></script>
</body>
</html>
- 第55行:可见服务器向客户端发送了一个名为[data]的数组,该数组包含对象[result:3],该对象已被集成到服务器页面[page1]的对象[data]中。 为了使客户端能够进行同样的操作,从而显示与服务器相同的页面,服务器向客户端传输对象 [result]。需要提醒的是,客户端不会执行函数 [asyncData],它只会使用服务器计算出的数据;
现在,让我们通过导航菜单从页面 [Home] 导航至页面 [Page 1]:

- 在 [1] 页面上,会看到进度条出现;
5秒后,页面变为[Page 1]:

日志如下:

可见客户端在页面生命周期开始前已执行了函数 [asyncData]。