Skip to content

14. 示例 [nuxt-11]:自定义加载图片

默认情况下,[nuxt] 的加载图片是一个进度条。示例 [nuxt-11] 展示了如何将其替换为自定义的加载图片:

Image

该 [nuxt-11] 示例还展示了如何处理加载错误。

Image

[nuxt-11] 示例最初源自 [nuxt-10] 示例:

Image

在 [1] 中,我们将为客户端添加一个插件,该插件将负责管理组件之间的事件。

14.1. [event-bus] 插件

[event-bus] 插件将在客户端和服务器端同时执行,但我们会发现它在服务器端无法正常工作。其代码如下:


// on crée un bus d'événements entre les vues
import Vue from 'vue'
export default (context, inject) => {
  // le bus d'événements
  const eventBus = new Vue()
  // injection d'une fonction [eventBus] dans le contexte
  inject('eventBus', () => eventBus)
}
  • 第 5 行:事件总线是 [Vue] 类的实例。该类提供了用于处理事件的方法:
    • [$emit]:用于触发事件;
    • [$on]:监听特定事件;

该事件总线仅处理一个事件 [loading],页面将利用该事件在等待异步函数完成时启动/停止加载动画;

  • 第 7 行:我们创建了一个名为 [$eventBus] 的函数(第一个参数),其作用是返回我们刚刚创建的 [eventBus] 对象(第二个参数)。该函数被注入到上下文中,以便在页面的 [context.app] 和 [this] 对象中可用;

14.2. [default.vue] 布局

[default.vue] 布局的演变如下:


<template>
  <div class="container">
    <b-card>
      <!-- un message -->
      <b-alert show variant="success" align="center">
        <h4>[nuxt-11] : personnalisation de l'attente, gestion des erreurs</h4>
      </b-alert>
      <!-- la vue courante du routage -->
      <nuxt />
      <!-- loading -->
      <b-alert v-if="showLoading" show variant="light">
        <strong>Requête au serveur de données en cours...</strong>
        <div class="spinner-border ml-auto" role="status" aria-hidden="true"></div>
      </b-alert>
      <!-- erreur de chargement -->
      <b-alert v-if="showErrorLoading" show variant="danger">
        <strong>La requête au serveur de données a échoué : {{ errorLoadingMessage }}</strong>
      </b-alert>
    </b-card>
  </div>
</template>
 
<script>
/* eslint-disable no-console */
export default {
  name: 'App',
  data() {
    return {
      showLoading: false,
      showErrorLoading: false
    }
  },
  // life cycle
  beforeCreate() {
    console.log('[default beforeCreate]')
  },
  created() {
    console.log('[default created]')
    // listen to the evt [loading]
    this.$eventBus().$on('loading', this.mShowLoading)
    // and the [errorLoadingMessage] event
    this.$eventBus().$on('errorLoading', this.mShowErrorLoading)
  },
  beforeMount() {
    console.log('[default beforeMount]')
  },
  mounted() {
    console.log('[default mounted]')
  },
  methods: {
    // load management
    mShowLoading(value) {
      console.log('[default mShowLoading], showLoading=', value)
      this.showLoading = value
    },
    // loading error
    mShowErrorLoading(value, errorLoadingMessage) {
      console.log('[default mShowErrorLoading], showErrorLoading=', value, 'errorLoadingMessage=', errorLoadingMessage)
      this.showErrorLoading = value
      this.errorLoadingMessage = errorLoadingMessage
    }
  }
}
</script>
  • 第 11–14 行:加载动画。仅当 [showLoading] 属性为 true(第 29 行)时才会显示;
  • 第 16–18 行:加载错误提示。仅当 [showErrorLoading] 属性(第 30 行)为 true 时才会显示;
  • 第 29–30 行:组件初始加载时,加载动画和错误消息均被隐藏;
  • 第 37–43 行:页面创建时,会监听插件创建的事件总线上的 [loading] 事件(第一个参数)。接收到该事件后,将执行第 52–55 行中的 [mShowLoading] 方法(第二个参数);
  • 第 52–55 行:[mShowLoading] 方法接收的参数为布尔值(true/false),用于显示或隐藏加载提示;
  • 第 41–42 行:页面创建时,会监听插件创建的事件总线上的 [errorLoading] 事件(第一个参数)。接收到该事件后,将执行第 57–61 行中的 [mShowErrorLoading] 方法(第二个参数);
  • 第 57 行:[mShowErrorLoading] 方法接受两个参数:
    • 第一个参数是一个布尔值(true/false),用于控制是否显示错误提示;
    • 第二个参数仅在发生错误时存在,它表示要显示的错误消息;
  • 第 53 行和第 58 行的日志将显示,[showLoading] 和 [showErrorLoading] 方法在服务器端并未被执行

14.3. [page1] 页面

[page1] 页面的代码如下所示:


<!-- vue n° 1 -->
<template>
  <Layout :left="true" :right="true">
    <!-- navigation -->
    <Navigation slot="left" />
    <!-- message-->
    <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 used
  components: {
    Layout,
    Navigation
  },
  // asynchronous data
  asyncData(context) {
    // log
    console.log('[page1 asyncData started]')
    // start waiting
    context.app.$eventBus().$emit('loading', true)
    // no error
    context.app.$eventBus().$emit('errorLoading', false)
    // we make a promise
    return new Promise(function(resolve, reject) {
      // we simulate an asynchronous function
      setTimeout(function() {
        // end waiting
        context.app.$eventBus().$emit('loading', false)
        // log
        console.log('[page1 asyncData finished]')
        // we make the result asynchronous - a random number here
        resolve({ result: Math.floor(Math.random() * Math.floor(100)) })
      }, 5000)
    })
  },
 
  // life cycle
  beforeCreate() {
    console.log('[page1 beforeCreate]')
  },
  created() {
    console.log('[page1 created]')
  },
  beforeMount() {
    console.log('[page1 beforeMount]')
  },
  mounted() {
    console.log('[page1 mounted]')
  }
}
</script>
  • 更改发生在第 26–47 行的 [asyncData] 函数中;
  • 第 29–30 行:在异步函数开始之前,会向应用程序的其他页面发出 [loading] 事件。请注意,在 [asyncData] 中,我们尚无法访问 [this] 对象,因为它尚未被创建。因此,我们使用作为参数传递给 [asyncData] 函数的上下文(第 26 行);
  • 第 30 行:使用事件总线来指示加载即将开始;
  • 第 38 行:我们使用事件总线来指示加载已完成;

注意:在运行时,当向服务器请求 [page1] 页面时,加载图标不会显示。在日志中,我们可以看到服务器端并未调用 [default.mShowLoading] 方法。 无论如何,在向服务器请求页面时显示加载图标毫无意义。只有当 [asyncData] 函数执行完毕后,服务器才会将页面发送给客户端浏览器。因此,加载图标是多余的。对于应用程序中所有直接从服务器请求的页面,情况均是如此。

14.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 */
/* eslint-disable nuxt/no-timing-in-fetch-data */
 
import Navigation from '@/components/navigation'
import Layout from '@/components/layout'
 
export default {
  name: 'Home',
  // components used
  components: {
    Layout,
    Navigation
  },
  // asynchronous data
  asyncData(context) {
    // log
    console.log('[page1 asyncData started]')
    // start waiting
    context.app.$eventBus().$emit('loading', true)
    // no error
    context.app.$eventBus().$emit('errorLoading', false)
    // we make a promise
    return new Promise(function(resolve, reject) {
      // we simulate an asynchronous function
      setTimeout(function() {
        // end waiting
        context.app.$eventBus().$emit('loading', false)
        // log
        console.log('[page1 asyncData finished]')
        // we return an error
        reject(new Error("le serveur n'a pas répondu assez vite"))
      }, 5000)
    }).catch((e) => context.error({ statusCode: 500, message: e.message }))
  },
  // life cycle
  beforeCreate() {
    console.log('[home beforeCreate]')
  },
  created() {
    console.log('[home created]')
  },
  beforeMount() {
    console.log('[home beforeMount]')
  },
  mounted() {
    console.log('[home mounted]')
    // no error
    this.$eventBus().$emit('errorLoading', false)
  }
}
</script>
  • 第 30–49 行:[asyncData] 函数与 [page1] 页面上的完全相同,只有一个例外:在第 46 行,异步函数在失败时会被终止(使用 [reject] 方法);
  • 第 46 行:[reject] 函数的参数是 [Error] 类的实例。而 [Error] 构造函数的参数则是错误消息;
  • 第 48 行:此错误由 [Promise] 的 [catch] 方法捕获,该方法将错误作为参数接收。随后我们使用 [context.error] 函数报告错误。此处 [context.error] 函数的参数是一个具有两个属性的对象:
    • [statusCode]:HTTP 错误代码;
    • [message]:错误消息;

无论 [asyncData] 是在客户端还是服务器端执行,一旦发生 [context.error] 错误,[nuxt] 都会显示 [layouts/error.vue] 页面:

Image

尽管它是一个页面,但 [error.vue] 页面是在 [layouts] 文件夹中查找的(可能是为了防止它被包含在应用程序的路由中?)。这里,[error.vue] 页面如下所示:


<!-- définition HTML de la vue -->
<template>
  <!-- mise en page -->
  <Layout :left="true" :right="true">
    <!-- alerte dans la colonne de droite -->
    <template slot="right">
      <!-- message sur fond jaune -->
      <b-alert show variant="danger" align="center">
        <h4>L'erreur suivante s'est produite : {{ JSON.stringify(error) }}</h4>
      </b-alert>
    </template>
    <!-- menu de navigation dans la colonne de gauche -->
    <Navigation slot="left" />
  </Layout>
</template>
 
<script>
/* eslint-disable no-undef */
/* eslint-disable no-console */
/* eslint-disable nuxt/no-env-in-hooks */
 
import Layout from '@/components/layout'
import Navigation from '@/components/navigation'
 
export default {
  name: 'Error',
  // components used
  components: {
    Layout,
    Navigation
  },
  // property [props]
  props: { error: { type: Object, default: () => 'waiting ...' } },
  // life cycle
  beforeCreate() {
    // client and server
    console.log('[error beforeCreate]')
  },
  created() {
    // client and server
    console.log('[error created, error=]', this.error)
  },
  beforeMount() {
    // customer only
    console.log('[error beforeMount]')
  },
  mounted() {
    // customer only
    console.log('[error mounted]')
  }
}
</script>

当 [nuxt] 渲染 [error.vue] 页面时,会将发生的错误作为 [props] 属性传递给该页面(第 33 行)。如果错误是由 [context.error(object1)] 引起的,那么 [error.vue] 页面的 [props] 属性将取值为 [object1]。 [nuxt] 文档指出,[object1] 必须至少包含 [statusCode, message] 这两个属性。第 9 行显示了接收到的 [object1] 对象的 JSON 字符串。

14.5. [page2] 页面

[page2] 页面展示了另一种处理错误的方式:

  • 在 [page1] 中,错误会在独立页面 [error.vue] 中显示;
  • 而在 [page2] 中,错误将显示在引发该错误的 [page2] 页面上;

[page2] 的代码如下:


<!-- vue n° 2 -->
<template>
  <Layout :left="true" :right="true">
    <!-- navigation -->
    <Navigation slot="left" />
    <!-- message -->
    <b-alert slot="right" show variant="secondary">
      Page 2
    </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: 'Page2',
  // components used
  components: {
    Layout,
    Navigation
  },
  // asynchronous data
  asyncData(context) {
    // log
    console.log('[page2 asyncData started]')
    // start waiting
    context.app.$eventBus().$emit('loading', true)
    // no error
    context.app.$eventBus().$emit('errorLoading', false)
    // we make a promise
    return new Promise(function(resolve, reject) {
      // we simulate an asynchronous function
      setTimeout(function() {
        // end waiting
        context.app.$eventBus().$emit('loading', false)
        // arbitrarily generate an error
        const errorLoadingMessage = "le serveur n'a pas répondu assez vite"
        // successful completion
        resolve({ showErrorLoading: true, errorLoadingMessage })
        // log
        console.log('[page2 asyncData finished]')
      }, 5000)
    })
  },
  // life cycle
  beforeCreate() {
    console.log('[page2 beforeCreate]')
  },
  created() {
    console.log('[page2 created]')
  },
  beforeMount() {
    console.log('[page2 beforeMount]')
  },
  mounted() {
    console.log('[page2 mounted]')
    // customer
    if (this.showErrorLoading) {
      console.log('[page2 mounted, showErrorLoading=true]')
      this.$eventBus().$emit('errorLoading', true, this.errorLoadingMessage)
    }
  }
}
</script>

我们再次将 [asyncData] 函数插入到页面代码中,与 [index] 类似,[page2] 也会引发一个错误,不过这次我们将采用不同的方式来处理它。

  • 第 44 行:服务器和客户端都通过返回结果 [{ showErrorLoading: true, errorLoadingMessage }] 成功解析了该 Promise。我们知道这会将 [showErrorLoading] 和 [errorLoadingMessage] 这两个属性添加到页面的 [data] 属性中,并且客户端将收到这些属性;
  • 第 60–67 行:我们知道 [mounted] 函数仅由客户端执行;
  • 第 63 行:客户端检查 [showErrorLoading] 属性是否已被设置(由服务器或客户端根据情况设置)。如果是,则触发 [‘errorLoading’] 事件(第 65 行),以便 [default] 页面显示错误消息 [this.errorLoadingMessage]。最终,服务器发送的页面上不会显示错误消息。 错误消息由客户端在页面“挂载”的最后一刻显示;

14.6. 执行

14.6.1. [nuxt.config]

[nuxt.config.js] 运行时文件如下:


export default {
  mode: 'universal',
  /*
   ** Headers of the page
   */
  head: {
    title: 'Introduction à [nuxt.js]',
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      {
        hid: 'description',
        name: 'description',
        content: 'ssr routing loading asyncdata middleware plugins store'
      }
    ],
    link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }]
  },
  /*
   ** Customize the progress-bar color
   */
  loading: false,
 
  /*
   ** Global CSS
   */
  css: [],
  /*
   ** Plugins to load before mounting the App
   */
  plugins: [{ src: '@/plugins/event-bus' }],
  /*
   ** Nuxt.js dev-modules
   */
  buildModules: [
    // Doc: https://github.com/nuxt-community/eslint-module
    '@nuxtjs/eslint-module'
  ],
  /*
   ** Nuxt.js modules
   */
  modules: [
    // Doc: https://bootstrap-vue.js.org
    'bootstrap-vue/nuxt',
    // Doc: https://axios.nuxtjs.org/usage
    '@nuxtjs/axios'
  ],
  /*
   ** Axios module configuration
   ** See https://axios.nuxtjs.org/options
   */
  axios: {},
  /*
   ** Build configuration
   */
  build: {
    /*
     ** You can extend webpack config here
     */
    extend(config, ctx) {}
  },
  // source code directory
  srcDir: 'nuxt-11',
  // router
  router: {
    // application URL root
    base: '/nuxt-11/'
  },
  // server
  server: {
    // service port, default 3000
    port: 81,
    // network addresses listened to, default localhost: 127.0.0.1
    // 0.0.0.0 = all the machine's network addresses
    host: 'localhost'
  }
}
  • 第 22 行:将 [loading] 属性设置为 [false],以便 [nuxt] 不使用其默认加载图片;
  • 第 31 行:定义事件总线的插件;

14.6.2. 服务器提供的 [index] 页面

让我们向服务器请求 [index] 页面(手动输入 URL [http://localhost:81/nuxt-11/])。客户端浏览器显示的页面如下:

Image

日志内容如下:

Image

  • 在 [3] 中,我们可以看到服务器发送了 [error.vue] 页面;
  • 在 [4] 中,我们看到客户端也显示了 [error] 页面,且错误信息与服务器端一致;
  • 我们可以看到,尽管 [index] 页面已触发等待,但服务器端并未调用 [default] 页面的 [mShowLoading] 方法。该方法是在接收到事件时被调用的,显然服务器端未实现事件处理;

让我们检查客户端浏览器接收到的页面源代码:


<!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-11/">
  <link rel="preload" href="/nuxt-11/_nuxt/runtime.js" as="script">
  <link rel="preload" href="/nuxt-11/_nuxt/commons.app.js" as="script">
  <link rel="preload" href="/nuxt-11/_nuxt/vendors.app.js" as="script">
  <link rel="preload" href="/nuxt-11/_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-11] : personnalisation de l'attente, gestion des erreurs</h4>
              </div>
            <div>
              <div class="row">
                <div class="col-2">
                  <ul class="nav flex-column">
                    <li class="nav-item">
                      <a href="/nuxt-11/" target="_self" class="nav-link active nuxt-link-active">
                        Home
                      </a>
                    </li>
                    <li class="nav-item">
                      <a href="/nuxt-11/page1" target="_self" class="nav-link">
                        Page 1
                      </a>
                    </li>
                    <li class="nav-item">
                      <a href="/nuxt-11/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" align="center" class="alert alert-danger">
                <h4>L'erreur suivante s'est produite : {&quot;statusCode&quot;:500,&quot;message&quot;:&quot;le serveur n'a pas répondu assez vite&quot;}</h4>
                    </div>
                </div>
              </div>
            </div>  
          </div>
        </div>
      </div>
    </div>
  </div>
  <script>window.__NUXT__ = (function (a, b, c, d) {
  d.statusCode = 500; d.message = "le serveur n'a pas répondu assez vite";
  return {
    layout: "default", data: [d], error: d, serverRendered: true,
    logs: [
      { date: new Date(1575047424168), args: ["[event-bus créé]"], type: a, level: b, tag: c },
      { date: new Date(1575047424175), args: ["[page1 asyncData started]"], type: a, level: b, tag: c },
      { date: new Date(1575047429455), args: ["[page1 asyncData finished]"], type: a, level: b, tag: c },
      { date: new Date(1575047429515), args: ["[default beforeCreate]"], type: a, level: b, tag: c },
      { date: new Date(1575047429675), args: ["[default created]"], type: a, level: b, tag: c },
      { date: new Date(1575047430157), args: ["[error beforeCreate]"], type: a, level: b, tag: c },
      { date: new Date(1575047430246), args: ["[error created, error=]", "{ statusCode: 500,\n  message: 'le serveur n\\'a pas répondu assez vite' }"], type: a, level: b, tag: c }]
  }
    }("log", 2, "", {}));</script>
  <script src="/nuxt-11/_nuxt/runtime.js" defer></script>
  <script src="/nuxt-11/_nuxt/commons.app.js" defer></script>
  <script src="/nuxt-11/_nuxt/vendors.app.js" defer></script>
  <script src="/nuxt-11/_nuxt/app.js" defer></script>
</body>
</html>
  • 第 57 行:我们看到服务器发送了一个对象 [d],该对象代表了服务器端发生的错误;
  • 第 59 行:我们看到一个名为 [error] 的属性,其值为对象 [d]。我们可以推断,正是服务器发送的页面中存在 [error] 属性,导致客户端脚本显示包含 [error] 错误的 [error.vue] 页面;

14.6.3. 由服务器执行的 [page1] 页面

我们手动输入 URL [http://localhost:81/nuxt-11/page1]。5 秒后,浏览器显示以下页面:

Image

显示的日志如下:

Image

  • 在 [1] 中,是服务器日志。请注意,[default] 页面的 [mShowLoading] 方法未被调用;
  • 在 [2] 中,客户端日志;

14.6.4. 由服务器执行的 [page2] 页面

我们手动输入 URL [http://localhost:81/nuxt-11/page2]。5 秒后,浏览器显示以下页面:

Image

让我们查看浏览器中显示的日志:

Image

  • 在 [1] 中,是服务器日志。回想一下,服务器在发送给客户端浏览器的页面中包含了 [showErrorLoading, errorLoadingMessage] 属性。我们知道,这些属性随后会被包含在客户端显示的页面的 [data] 中
  • 在 [3] 中,当 [page2] 页面挂载时,它发现 [showErrorLoading] 属性被设置为 true。随后它向 [default] 页面发送了一个事件,使其显示服务器发送的错误消息 [4];

14.6.5. 客户端执行的 [index] 页面

现在我们使用导航链接来显示这三个页面。客户端显示的所有页面与服务器显示的完全一致。唯一的区别在于每次都会显示 5 秒的加载图片。

我们从 [index] 页面开始。随后显示加载图片:

Image

5秒后,将显示以下页面:

Image

因此,最终页面与服务器端生成的页面完全一致。

Image

回顾 [index] 页面上的 [asyncData] 函数:


asyncData(context) {
    // log
    console.log('[page1 asyncData started]')
    // start waiting
    context.app.$eventBus().$emit('loading', true)
    // no error
    context.app.$eventBus().$emit('errorLoading', false)
    // we make a promise
    return new Promise(function(resolve, reject) {
      // we simulate an asynchronous function
      setTimeout(function() {
        // end waiting
        context.app.$eventBus().$emit('loading', false)
        // log
        console.log('[page1 asyncData finished]')
        // we return an error
        reject(new Error("le serveur n'a pas répondu assez vite"))
      }, 5000)
    }).catch((e) => context.error({ statusCode: 500, message: e.message }))
}

客户端日志如下:

Image

  • 在 [1] 中,[asyncData] 函数开始执行;
  • 在 [2],显示加载图片;
  • 在 [2-3] 中,我们可以看到 [default] 页面已收到由 [index] 页面的 [asyncData] 函数发送的 [loading, true] [2] 和 [errorLoading, false] 事件(第 5 行和第 7 行);
  • 在 [4],等待结束。[default] 页面已收到由 [index] 页面发送的 [loading, false] 事件(第 13 行);
  • 在 [5] 中,[asyncData] 函数已完成其工作;
  • 由于 [asyncData] 函数触发了 [context.error] 错误(第 19 行),因此显示 [error] 页面 [6];

14.6.6. 客户端执行的 [page1] 页面

等待 5 秒后,客户端显示以下页面:

Image

让我们回顾一下 [page1] 中 [asyncData] 函数的代码:


asyncData(context) {
    // log
    console.log('[page1 asyncData started]')
    // start waiting
    context.app.$eventBus().$emit('loading', true)
    // no error
    context.app.$eventBus().$emit('errorLoading', false)
    // we make a promise
    return new Promise(function(resolve, reject) {
      // we simulate an asynchronous function
      setTimeout(function() {
        // end waiting
        context.app.$eventBus().$emit('loading', false)
        // log
        console.log('[page1 asyncData finished]')
        // we make the result asynchronous - a random number here
        resolve({ result: Math.floor(Math.random() * Math.floor(100)) })
      }, 5000)
    })
},

日志如下:

Image

14.6.7. 客户端执行的 [page2] 页面

等待 5 秒后,客户端显示以下页面:

Image

让我们回顾一下 [page2] 中 [asyncData] 和 [mounted] 函数的代码:


asyncData(context) {
    // log
    console.log('[page2 asyncData started]')
    // start waiting
    context.app.$eventBus().$emit('loading', true)
    // no error
    context.app.$eventBus().$emit('errorLoading', false)
    // we make a promise
    return new Promise(function(resolve, reject) {
      // we simulate an asynchronous function
      setTimeout(function() {
        // end waiting
        context.app.$eventBus().$emit('loading', false)
        // arbitrarily generate an error
        const errorLoadingMessage = "le serveur n'a pas répondu assez vite"
        // successful completion
        resolve({ showErrorLoading: true, errorLoadingMessage })
        // log
        console.log('[page2 asyncData finished]')
      }, 5000)
    })
  }
 
mounted() {
    console.log('[page2 mounted]')
    // customer
    if (this.showErrorLoading) {
      console.log('[page2 mounted, showErrorLoading=true]')
      this.$eventBus().$emit('errorLoading', true, this.errorLoadingMessage)
    }
}

日志如下:

Image

  • 在 [1] 中,[default] 页面接收到了由 [page2] 发送的 [showErrorLoading, true] 事件(第 29 行),该事件指示其显示错误消息;