Skip to content

10. 示例 [nuxt-07]:客户端与服务器上下文

10.1. 简介

示例 [nuxt-07] 旨在探讨服务器端和客户端的 [context] 对象。需要记住的是,[nuxt] 应用程序的这两个组件是相互独立的:除了以下内容外,它们没有任何共享

  • 服务器选择发送给客户端的内容(包含在 HTTP 响应和渲染的页面中);
  • 客户端选择发送给服务器的内容(通过其 HTTP 请求);

因此,正如我们将看到的,尽管服务器端和客户端处理的对象名称相同,但它们并非同一实体:它们有时可能是彼此的副本,但绝不会拥有相同的引用。修改客户端对象不会影响服务器端同名对象,反之亦然。

示例 [nuxt-07] 最初是通过复制示例 [nuxt-01] 获得的:

Image

  • 在 [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. 由服务器执行的插件

运行时,服务器会显示以下内容:

[main server], process.server= true process.client= false
[main server], il y a 2 arguments
Liste des clés [[main server], context]
[
  'isStatic',
  'isDev',
  'isHMR',
  'app',
  'payload',
  'error',
  'base',
  'env',
  'req',
  'res',
  'ssrContext',
  'redirect',
  'beforeNuxtRender',
  'route',
  'next',
  '_redirected',
  '_errored',
  'params',
  'query',
  '$axios'
]
  • 第 11–12 行:我们之前已经用过 [base] 和 [env] 属性,它们的值来自 [nuxt.config.js] 文件;
  • 第 8 行:[app] 属性指代 [nuxt] 应用程序;
  • 第 18 行:[route] 属性指路由器的当前路由,即服务器将发送的页面;
  • 第 13 行:来自客户端浏览器的 HTTP 请求;
  • 第 14 行:服务器的 HTTP 响应;

[context.app] 属性的列表如下:

Liste des clés [[main server], context.app]
[
  'router',
  'nuxt',
  'head',
  'render',
  'data',
  'beforeCreate',
  'created',
  'mounted',
  'watch',
  'computed',
  'methods',
  'components',
  'context',
  '$axios'
]
  • 第 3 行:[router] 属性使我们能够访问应用程序的路由器。这在 [Nuxt] 中非常重要,因为路由器是由 [Nuxt] 自身定义的,而非由开发者定义。该属性允许开发者修改路由器;

[context.route] 的属性列表如下:

Liste des clés [[main server], context.route]
[
  'name',
  'meta',
  'path',
  'hash',
  'query',
  'params',
  'fullPath',
  'matched'
]

服务器启动时的路由 [context.route] 如下:

[main server], context.route= {
  name: 'index',
  meta: [
    {}
  ],
  path: '/',
  hash: '',
  query: {},
  params: {},
  fullPath: '/',
  matched: [
    {
      path: '',
      regex: /^(?:\/(?=$))?$/i,
      components: [Object],
      instances: {},
      name: 'index',
      parent: undefined,
      matchAs: undefined,
      redirect: undefined,
      beforeEnter: undefined,
      meta: {},
      props: {}
    }
  ]
}
  • 第 2 行:我们可以看到服务器上的下一页是 [index],其路径为 [/](第 10 行);
  • 第 22 行:[meta] 属性允许您为路由添加属性;

服务器 [context.app.router] 的属性如下:

Liste des clés [[main server], context.app.router]
[
  'app',
  'apps',
  'options',
  'beforeHooks',
  'resolveHooks',
  'afterHooks',
  'matcher',
  'fallback',
  'mode',
  'history'
]

应用程序的各种路由位于 [context.app.router.options.routes] 属性中:

Liste des clés [[main server], context.app.router.options.routes]
[
  '0',
  '1',
  '2'
]
[main server], context.app.router.options.routes= [
  {
    path: '/page1',
    component: [Function: _d7b6c762],
    name: 'page1'
  },
  {
    path: '/page2',
    component: [Function: _d79a9860],
    name: 'page2'
  },
  {
    path: '/',
    component: [Function: _31eaad9f],
    name: 'index'
  }
]

最后,第二个论点:

inject= function

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] 对象的属性;

当由服务器执行时,该页面会生成以下日志:

[home beforeCreate]
[home server created]
Liste des clés [[home server created], this.$nuxt]
[
  '_uid',
  '_isVue',
  '$options',
  '_renderProxy',
  '_self',
  '$parent',
  '$root',
  '$children',
  '$refs',
  '_watcher',
  '_inactive',
  '_directInactive',
  '_isMounted',
  '_isDestroyed',
  '_isBeingDestroyed',
  '_events',
  '_hasHookEvent',
  '_vnode',
  '_staticTrees',
  '$vnode',
  '$slots',
  '$scopedSlots',
  '_c',
  '$createElement',
  '$attrs',
  '$listeners',
  '_routerRoot',
  '_router',
  '_route',
  '_bv__modal',
  '_bv__toast',
  '_vueMeta',
  'nuxt',
  '_watchers',
  'refreshOnlineStatus',
  'refresh',
  'errorChanged',
  'setLayout',
  'loadLayout',
  '_data',
  'layoutName',
  'layout',
  'isOnline',
  '_computedWatchers',
  'isOffline',
  'error',
  'context'
]

[index] 页面上的服务器上下文属性如下:

Liste des clés [[home server created], this.$nuxt.context]
[
  'isStatic',
  'isDev',
  'isHMR',
  'app',
  'payload',
  'error',
  'base',
  'env',
  'req',
  'res',
  'ssrContext',
  'redirect',
  'beforeNuxtRender',
  'route',
  'next',
  '_redirected',
  '_errored',
  'params',
  'query',
  '$axios'
]

这些属性与插件的 [context] 对象中的属性相同。

10.5. 由客户端执行的插件

一旦服务器将 [index] 页面发送至客户端浏览器,客户端脚本便会接管。随后将执行 [main.js] 插件。相关日志如下:

[main server], process.server= false process.client= true
[main client], il y a 2 arguments
Liste des clés [[main client], context]
Array(17)0: "isStatic"1: "isDev"2: "isHMR"3: "app"4: "payload"5: "error"6: "base"7: "env"8: "redirect"9: "nuxtState"10: "route"11: "next"12: "_redirected"13: "_errored"14: "params"15: "query"16: "$axios"length: 17__proto__: Array(0)
Liste des clés [[main client], context.app]
Array(14)0: "router"1: "nuxt"2: "head"3: "render"4: "data"5: "beforeCreate"6: "created"7: "mounted"8: "watch"9: "computed"10: "methods"11: "components"12: "context"13: "$axios"length: 14__proto__: Array(0)
Liste des clés [[main client], context.route]
Array(8)0: "name"1: "meta"2: "path"3: "hash"4: "query"5: "params"6: "fullPath"7: "matched"length: 8__proto__: Array(0)
[main client], context.route= ObjectfullPath: "/"hash: ""matched: [{}]meta: [{}]name: "index"params: {}path: "/"query: {}__proto__: Object
Liste des clés [[main client], context.app.router]
Array(10)0: "app"1: "apps"2: "options"3: "beforeHooks"4: "resolveHooks"5: "afterHooks"6: "matcher"7: "fallback"8: "mode"9: "history"length: 10__proto__: Array(0)
Liste des clés [[main client], context.app.router.options.routes]
Array(3)0: "0"1: "1"2: "2"length: 3__proto__: Array(0)
[main client], context.app.router.options.routes= Array(3)0: {path: "/page1", name: "page1", component: ƒ}1: {path: "/page2", name: "page2", component: ƒ}2: {path: "/", name: "index", component: ƒ}length: 3__proto__: Array(0)
inject= function

我们发现了一些与服务器端类似的属性,但有些属性缺失,有些则出现了。例如,在第 4 行中,[req, res] 属性(即客户端浏览器的 HTTP 请求和服务器的 HTTP 响应)缺失了。

10.6. 客户端的 [index] 页面

客户端的 [index] 页面会生成以下日志:

1
2
3
4
5
6
7
8
[home beforeCreate]
[home client created]
Liste des clés [[home client created], this.$nuxt]
(51) ["_uid", "_isVue", "$options", "_renderProxy", "_self", "$parent", "$root", "$children", "$refs", "_watcher", "_inactive", "_directInactive", "_isMounted", "_isDestroyed", "_isBeingDestroyed", "_events", "_hasHookEvent", "_vnode", "_staticTrees", "$vnode", "$slots", "$scopedSlots", "_c", "$createElement", "$attrs", "$listeners", "_routerRoot", "_router", "_route", "_bv__modal", "_bv__toast", "_vueMeta", "nuxt", "_watchers", "refreshOnlineStatus", "refresh", "errorChanged", "setLayout", "loadLayout", "_data", "layoutName", "layout", "isOnline", "_computedWatchers", "isOffline", "error", "context", "_name", "setTransitions", "$loading", "$el"]
Liste des clés [[home client created], this.$nuxt.context]
(17) ["isStatic", "isDev", "isHMR", "app", "payload", "error", "base", "env", "redirect", "nuxtState", "route", "next", "_redirected", "_errored", "params", "query", "$axios"]
[home client beforeMount]
[home client mounted]
  • 第 4 行:[this.$nuxt] 对象的属性。这是一个包含 51 个属性的丰富对象;
  • 第 6 行:[this.$nuxt.context] 对象的属性。这些属性与客户端插件的 [context] 对象中的属性相同;