10. 示例 [nuxt-07]:客户端与服务器上下文
10.1. 简介
示例 [nuxt-07] 旨在探讨服务器端和客户端的 [context] 对象。需要记住的是,[nuxt] 应用程序的这两个组件是相互独立的:除了以下内容外,它们没有任何共享:
- 服务器选择发送给客户端的内容(包含在 HTTP 响应和渲染的页面中);
- 客户端选择发送给服务器的内容(通过其 HTTP 请求);
因此,正如我们将看到的,尽管服务器端和客户端处理的对象名称相同,但它们并非同一实体:它们有时可能是彼此的副本,但绝不会拥有相同的引用。修改客户端对象不会影响服务器端同名对象,反之亦然。
示例 [nuxt-07] 最初是通过复制示例 [nuxt-01] 获得的:

- 在 [2] 中,我们将添加一个客户端和服务器端共用的插件;
- 在 [3] 中,我们将对 [index] 页面进行微调;
10.2. [common / main.js] 插件
[common / main.js] 插件由客户端和服务器端共同执行:这是由于以下 [nuxt.config.js] 配置所致:
/*
** Plugins to load before mounting the App
*/
plugins: [{ src: '~/plugins/common/main.js' }],
- 第 4 行:由于缺少 [mode] 属性,表示 [~/plugins/common/main.js] 插件将由客户端和服务器端共同执行:先由服务器端执行,然后由客户端执行;
该插件将如下所示:
/* eslint-disable no-undef */
/* eslint-disable no-console */
export default function(...args) {
// who executes this code?
console.log('[main server], process.server=', process.server, 'process.client=', process.client)
const who = process.server ? 'server' : 'client'
const main = '[main ' + who + ']'
// number of arguments
console.log(main + ', il y a', args.length, 'arguments')
// 1st argument
const context = args[0]
// key context
dumpkeys(main + ', context', context)
// the application
dumpkeys(main + ', context.app', context.app)
// the road
dumpkeys(main + ', context.route', context.route)
console.log(main + ', context.route=', context.route)
// the router
dumpkeys(main + ', context.app.router', context.app.router)
// on router.options.routes
dumpkeys(main + ', context.app.router.options.routes', context.app.router.options.routes)
console.log(main + ', context.app.router.options.routes=', context.app.router.options.routes)
// 2nd argument
const inject = args[1]
console.log('inject=', typeof inject)
}
function dumpkeys(message, object) {
// list of [object] keys
const ligne = 'Liste des clés [' + message + ']'
console.log(ligne)
// kEY LIST
if (object) {
console.log(Object.keys(object))
}
}
- 第 31–39 行:[dumpkeys] 函数列出了作为第二个参数传递的对象的属性。该列表前会显示作为第一个参数传递的消息;
- 第 3 行:我们需要知道该函数接收了多少个参数。为此,我们使用 [...args] 语法,它会将实际的函数参数放入 [args] 数组中。我们会发现共有两个参数;
- 第 5 行:我们显示代码的执行方,是服务器还是客户端;
- 第 6 行:代码执行者,客户端或服务器;
- 第 7 行:日志中使用的字符串常量;
- 第 12 行:我们将看到插件接收到的第一个参数是执行者的上下文;
- 第 14 行:[context] 对象的键列表;
- 第 16 行:我们将看到 [context] 对象有一个 [app] 属性,它代表 [nuxt] 应用程序;
- 第 18 行:我们会看到 [context] 对象有一个 [route] 属性,代表路由器的当前路由;
- 第 21 行:我们会发现 [app] 对象有一个 [router] 属性,它代表路由器;
- 第 23 行:[router.options.routes] 对象代表应用程序的各种路由;
- 第 27–28 行:插件的第二个参数是我们在 [nuxt-06] 示例中使用的 [inject] 函数;
10.3. 由服务器执行的插件
运行时,服务器会显示以下内容:
- 第 11–12 行:我们之前已经用过 [base] 和 [env] 属性,它们的值来自 [nuxt.config.js] 文件;
- 第 8 行:[app] 属性指代 [nuxt] 应用程序;
- 第 18 行:[route] 属性指路由器的当前路由,即服务器将发送的页面;
- 第 13 行:来自客户端浏览器的 HTTP 请求;
- 第 14 行:服务器的 HTTP 响应;
[context.app] 属性的列表如下:
- 第 3 行:[router] 属性使我们能够访问应用程序的路由器。这在 [Nuxt] 中非常重要,因为路由器是由 [Nuxt] 自身定义的,而非由开发者定义。该属性允许开发者修改路由器;
[context.route] 的属性列表如下:
服务器启动时的路由 [context.route] 如下:
- 第 2 行:我们可以看到服务器上的下一页是 [index],其路径为 [/](第 10 行);
- 第 22 行:[meta] 属性允许您为路由添加属性;
服务器 [context.app.router] 的属性如下:
应用程序的各种路由位于 [context.app.router.options.routes] 属性中:
最后,第二个论点:
10.4. 服务器的 [index] 页面
[index] 页面如下:
<!-- page principale -->
<template>
<Layout :left="true" :right="true">
<!-- navigation -->
<Navigation slot="left" />
<!-- message-->
<b-alert slot="right" show variant="warning">
Home
</b-alert>
</Layout>
</template>
<script>
/* eslint-disable no-undef */
/* eslint-disable no-console */
/* eslint-disable nuxt/no-env-in-hooks */
import Navigation from '@/components/navigation'
import Layout from '@/components/layout'
export default {
name: 'Home',
// components used
components: {
Layout,
Navigation
},
data() {
return {
who: process.server ? 'server' : 'client'
}
},
// life cycle
beforeCreate() {
// client and server
console.log('[home beforeCreate]')
},
created() {
// client and server
console.log('[home ' + this.who + ' created]')
this.dumpkeys('[home ' + this.who + ' created], this.$nuxt', this.$nuxt)
this.dumpkeys('[home ' + this.who + ' created], this.$nuxt.context', this.$nuxt.context)
},
beforeMount() {
// customer only
console.log('[home ' + this.who + ' beforeMount]')
},
mounted() {
// customer only
console.log('[home ' + this.who + ' mounted]')
},
methods: {
dumpkeys(message, object) {
// list of [object] keys
const ligne = 'Liste des clés [' + message + ']'
console.log(ligne)
if (object) {
console.log(Object.keys(object))
}
}
}
}
</script>
- 第 43 行:我们已经看到,页面的上下文可以在 [this.$nuxt.context] 中找到;
- 第 42 行:我们还展示了 [this.$nuxt] 对象的属性;
当由服务器执行时,该页面会生成以下日志:
[index] 页面上的服务器上下文属性如下:
这些属性与插件的 [context] 对象中的属性相同。
10.5. 由客户端执行的插件
一旦服务器将 [index] 页面发送至客户端浏览器,客户端脚本便会接管。随后将执行 [main.js] 插件。相关日志如下:
我们发现了一些与服务器端类似的属性,但有些属性缺失,有些则出现了。例如,在第 4 行中,[req, res] 属性(即客户端浏览器的 HTTP 请求和服务器的 HTTP 响应)缺失了。
10.6. 客户端的 [index] 页面
客户端的 [index] 页面会生成以下日志:
- 第 4 行:[this.$nuxt] 对象的属性。这是一个包含 51 个属性的丰富对象;
- 第 6 行:[this.$nuxt.context] 对象的属性。这些属性与客户端插件的 [context] 对象中的属性相同;