使用 Nuxt.js 实现简单的服务器端渲染、路由和页面过渡

Avatar of Sarah Drasner
Sarah Drasner

DigitalOcean 为您旅程的每个阶段提供云产品。 立即开始使用 200 美元的免费信用额度!

这个标题有点长,对吧? 什么是服务器端渲染? 它与路由和页面过渡有什么关系? Nuxt.js 是什么鬼? 很有意思的是,尽管听起来很复杂,但使用 Nuxt.js 并探索它的好处并不太难。 让我们开始吧!

服务器端渲染

您可能最近听到人们谈论服务器端渲染。 我们最近研究了 使用 React 进行服务器端渲染的一种方法。 一个特别引人注目的方面是性能优势。 当我们在服务器上渲染 HTML、CSS 和 JavaScript 时,我们通常需要解析的 JavaScript 更少,无论是在初始渲染还是后续更新时。 这篇文章 很好地深入探讨了这个主题。 我最喜欢的收获是

通过在服务器上渲染,您可以缓存数据的最终形式。

与其从服务器获取 JSON 或其他信息,解析它,然后使用 JavaScript 创建该信息的布局,不如在前面进行大量的计算,只发送我们需要的实际 HTML、CSS 和 JavaScript。 这可以为缓存、SEO 和加快应用程序和网站速度带来很多好处。

什么是 Nuxt.js?

服务器端渲染听起来很不错,但是您可能想知道它是否难以设置。 我最近一直在使用 Nuxt.js 来开发我的 Vue 应用程序,发现它非常易于使用。 需要明确的是:您无需专门使用 Nuxt.js 来进行服务器端渲染。 我只是出于很多原因喜欢这个工具。 我上个月进行了一些测试,发现 Nuxt.js 甚至比 Vue 的 PWA 模板具有更高的 lighthouse 得分,我认为这令人印象深刻。

Nuxt.js 是一个更高级别的框架,您可以使用 CLI 命令来创建通用 Vue 应用程序。 以下是部分好处(并非全部):

  • 服务器端渲染
  • 自动代码拆分
  • 强大的路由系统
  • 出色的 lighthouse 得分 🐎
  • 静态文件服务
  • ES6/ES7 转译
  • 开发中的热重载
  • 预处理器:SASS、LESS、Stylus 等
  • 编写 Vue 文件来创建页面和布局!
  • 我最喜欢的一个功能:轻松 为页面添加过渡效果

让我们使用一些路由来设置一个基本应用程序,亲身体验它的好处。

设置

如果您还没有安装 Vue 的 CLI,那么需要做的第一件事就是下载它。 您可以使用以下命令全局安装它

npm install -g vue-cli

# ... or ...
 
yarn add global vue-cli

您只需要执行一次,无需每次使用时都执行。

接下来,我们将使用 CLI 来搭建一个新项目,但我们将使用 Nuxt.js 作为模板

vue init nuxt/starter my-project
cd my-project
yarn  # or...  npm install
npm run dev

您将看到应用程序构建的进度,它将为您提供一个专用的开发服务器以供查看:http://127.0.0.1:3000/。 这就是您一开始将看到的内容(带有非常酷的小动画)

Screenshot of Nuxt starting screen

让我们看一下目前创建应用程序初始视图的内容。 我们可以转到 `pages` 目录,并在其中看到一个 `index.vue` 页面。 如果我们打开它,我们将看到创建该页面所用的所有标记。 我们还将看到它是一个 `.vue` 文件,使用单文件组件,就像任何普通的 `vue` 文件一样,带有用于 HTML 的模板标签、用于脚本的脚本标签(我们在其中导入了一个组件)以及样式标签中的一些样式。(如果您不熟悉这些,可以 在这里了解有关它们的更多信息。) 最酷的一点是,这个 `.vue` 文件不需要任何特殊设置。 它位于 `pages` 目录中,Nuxt.js 将自动将其转换为服务器端渲染的页面!

让我们创建一个新页面,并在它们之间设置一些路由。 在 `pages/index.vue` 中,删除现有的内容,并用以下内容替换它

<template>
  <div class="container">
    <h1>Welcome!</h1>
    <p><nuxt-link to="/product">Product page</nuxt-link></p>
  </div>
</template>

<style>
.container {
  font-family: "Quicksand", "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; /* 1 */
  padding: 60px;
}
</style>

然后,我们在 pages 目录中创建一个名为 `product.vue` 的新页面,并将以下内容放入其中

<template>
  <div class="container">
    <h1>This is the product page</h1>
    <p><nuxt-link to="/">Home page</nuxt-link></p>
  </div>
</template>

您会立即看到以下内容

就这样! 🏆
我们立即拥有服务器端渲染、页面之间的路由(如果您查看 URL,您会看到它在索引页面和产品页面之间切换),甚至还有一个很酷的绿色加载器,它在顶部快速移动。 我们没有做太多工作 来实现它。

您可能已经注意到,这里有一个特殊的元素:<nuxt-link to="/">。 这个标签可以像 a 标签一样使用,它包含一些内容,并将在我们的页面之间设置内部路由链接。 我们将使用 to="/page-title-here" 而不是 href

现在,让我们添加一些过渡效果。 我们将分几个阶段进行:从简单到复杂。

创建页面过渡效果

我们已经有一个非常酷的进度条,它在我们在路由时会在屏幕顶部运行,使整个过程感觉非常快。(那是一个专业的术语)。 虽然我很喜欢它,但它并不适合我们正在前进的方向,所以现在让我们把它去掉。

我们将进入我们的 `nuxt.config.js` 文件,并将以下行

/*
** Customize the progress-bar color
*/
loading: { color: '#3B8070' },

更改为

loading: false,

您还会在这个 `nuxt.config.js` 文件中注意到一些其他内容。 您会看到我们的元数据和头部标签,以及将在它们内部渲染的内容。 这是因为我们不会像在普通 CLI 构建中那样使用传统的 `index.html` 文件,Nuxt.js 将解析并构建我们的 `index.vue` 文件以及这些标签,然后在服务器上为我们渲染内容。 如果您需要添加 CSS 文件、字体或类似内容,我们将使用此 Nuxt.js 配置文件来执行此操作。

现在我们已经完成所有设置,让我们了解可以使用哪些方法来创建页面过渡效果。 为了了解我们正在插入页面的内容,我们需要回顾 Vue 中过渡组件的工作原理。 我在这里 写了一篇文章专门介绍这个主题,如果您想了解更多,可以查看它。 但是您真正需要了解的是:在幕后,Nuxt.js 将接入 Vue 的 `transition` 组件的功能,并为我们提供一些默认值和钩子来使用

transition component hooks

您可以在此处看到,我们有一个钩子用于指定动画开始前的操作 enter、动画/过渡期间的操作 enter-active 以及动画结束后的操作。 我们在元素离开时也有相同的钩子,只是在前面加上了 leave。 我们可以创建简单的过渡,这些过渡只是在状态之间进行插值,或者我们可以将完整的 CSS 或 JavaScript 动画插入其中。

通常在 Vue 应用程序中,为了使用这个漂亮的小功能,我们会将组件或元素包装在 <transition> 中,但 Nuxt.js 会在开始时为我们提供这个功能。 我们页面的钩子将以 page 开头,这真是太好了。 我们要做的就是在页面之间创建动画,就是在 CSS 中添加一些代码,以接入这些钩子

.page-enter-active, .page-leave-active {
  transition: all .25s ease-out;
}
.page-enter, .page-leave-active {
  opacity: 0;
  transform-origin: 50% 50%;
}

我还将在此处添加一些额外的样式,这样您就可以更容易地看到页面过渡效果

html, body {
  font-family: "Quicksand", "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; /* 1 */
  background: #222;
  color: white;
  width: 100vw;
  height: 100vh;
}

a, a:visited {
  color: #3edada;
  text-decoration: none;
}

.container {
  padding: 60px;
  width: 100vw;
  height: 100vh;
  background: #444;
}

目前,我们正在使用 CSS 过渡效果。 这只允许我们指定在两种状态之间转换过程中的操作。 我们可以通过让动画以暗示某些东西从何处而来以及去往何处的样式进行调整来创建一些更有趣的效果。 为此,我们可以将页面进入和页面离开激活类分开,但使用 CSS 动画来指定某些东西从何处而来以及去往何处,并将它们接入 .page-enter-active.page-leave-active 会更加简洁

.page-enter-active {
  animation: acrossIn .45s ease-out both;
} 

.page-leave-active {
  animation: acrossOut .65s ease-in both;
} 

@keyframes acrossIn {
  0% {
    transform: translate3d(-100%, 0, 0);
  }
  100% {
    transform: translate3d(0, 0, 0);
  }
}

@keyframes acrossOut {
  0% {
    transform: translate3d(0, 0, 0);
  }
  100% {
    transform: translate3d(100%, 0, 0);
  }
}

我们还将为产品页面添加一些特殊样式,这样我们可以看到这两个页面之间的区别

<style scoped>
  .container {
    background: #222;
  }
</style>

这个作用域标签非常酷,因为它只将样式应用于此页面/vue 文件。 如果您听说过 CSS 模块,您会熟悉这个概念。

我们会看到以下效果(此页面仅用于演示目的,对于典型的页面过渡来说,移动量可能太多了)

现在,假设我们有一个页面具有完全不同的交互方式。 对于这个页面,上下移动过于频繁,我们只想要一个简单的淡入淡出效果。 针对这种情况,我们需要重命名过渡钩子,以便将其与其他过渡分开。

让我们创建一个名为联系页面的新页面,并在 pages 目录中创建它。

<template>
  <div class="container">
    <h1>This is the contact page</h1>
    <p><nuxt-link to="/">Home page</nuxt-link></p>
  </div>
</template>

<script>
export default {
  transition: 'fadeOpacity'
}
</script>

<style>
.fadeOpacity-enter-active, .fadeOpacity-leave-active {
  transition: opacity .35s ease-out;
}

.fadeOpacity-enter, .fadeOpacity-leave-active {
  opacity: 0;
}
</style>

现在我们可以实现两页之间的过渡动画。

您可以看到我们可以如何在此基础上进一步构建,并为每个页面创建更多、更流畅的 CSS 动画。但从这里开始,让我们深入我喜欢的 JavaScript 动画,并用更强大的功能创建页面过渡。

JavaScript 钩子

Vue 的 <transition> 组件提供了一些钩子,用于使用 JavaScript 动画代替 CSS。它们如下所示,每个钩子都是可选的。:css="false" 绑定让 Vue 知道我们将使用 JS 来实现此动画。

<transition 
  @before-enter="beforeEnter"
  @enter="enter"
  @after-enter="afterEnter"
  @enter-cancelled="enterCancelled"

  @before-Leave="beforeLeave"
  @leave="leave"
  @after-leave="afterLeave"
  @leave-cancelled="leaveCancelled"
  :css="false">
 
 </transition>

我们还可以使用过渡模式。我很喜欢它们,因为您可以声明一个动画将等待另一个动画完成过渡后再开始过渡。我们将使用名为 out-in 的过渡模式。

我们可以用 JavaScript 和过渡模式做一些非常酷的事情,再次强调,为了演示的目的,我们会做一些比较夸张的事情,通常情况下我们会做一些更微妙的事情。

为了实现这样的效果,我运行了 yarn add gsap,因为我将使用 GreenSock 来实现此动画。在我的 `index.vue` 页面中,我可以删除现有的 CSS 动画,并将这段代码添加到 <script> 标签中。

import { TweenMax, Back } from 'gsap'

export default {
  transition: {
    mode: 'out-in',
    css: false,
    beforeEnter (el) {
      TweenMax.set(el, {
        transformPerspective: 600,
        perspective: 300,
        transformStyle: 'preserve-3d'
      })
    },
    enter (el, done) {
      TweenMax.to(el, 1, {
        rotationY: 360,
        transformOrigin: '50% 50%',
        ease: Back.easeOut
      })
      done()
    },
    leave (el, done) {
      TweenMax.to(el, 1, {
        rotationY: 0,
        transformOrigin: '50% 50%',
        ease: Back.easeIn
      })
      done()
    }
  }
}

所有这些演示的代码都存在于我的 Intro to Vue 仓库 中,如果您想学习 Vue 的入门材料,可以参考这些代码。

我想在这里提一点,目前 Nuxt.js 中的过渡模式存在一个 bug。这个 bug 已经修复,但还没有发布。它应该在即将发布的 1.0 版本中完全修复并更新,但在此之前,这里有一个 简单的示例演示,以及 跟踪该问题的 issue

有了这个有效的代码和 JavaScript 钩子,我们可以开始创建更加花哨的动画,并在每个页面上创建独特的过渡效果。

如果您想查看演示的实际效果,请访问以下网站:https://nuxt-type.now.sh/,以及包含代码的仓库:https://github.com/sdras/nuxt-type

导航

在最后一个演示中,您可能已经注意到,我们在所有路由页面上都使用了相同的导航。为了创建它,我们可以进入 `layouts` 目录,我们会看到一个名为 `default.vue` 的文件。这个目录将存放所有页面的基本布局,“default” 就是,嗯,默认的布局 :)

你会立刻看到这个

<template>
  <div>
    <nuxt/>
  </div>
</template>

特殊的 <nuxt/> 标签将是我们的 `.vue` 页面文件被插入的地方,所以为了创建导航,我们可以插入一个这样的导航组件。

<template>
  <div>
    <img class="moon" src="~assets/FullMoon2010.png" />
    <Navigation />
    <nuxt/>
  </div>
</template>

<script>
import Navigation from '~components/Navigation.vue'

export default {
  components: {
    Navigation
  }
}
</script>

我喜欢这样,因为所有东西都被很好地组织起来,区分了全局和局部需求。

然后,我在一个名为 `components` 的目录中有一个名为 Navigation 的组件(这在 Vue 应用中非常常见)。在这个文件中,你会看到一些指向不同页面的链接。

<nav>
  <div class="title">
    <nuxt-link to="/rufina">Rufina</nuxt-link>
    <nuxt-link to="/prata">Prata</nuxt-link>
    <nuxt-link exact to="/">Playfair</nuxt-link>
  </div>
</nav>

你会注意到,即使它在另一个目录中,我仍然使用 <nuxt-link> 标签,路由仍然可以正常工作。但是,最后一页有一个额外的属性,即 exact 属性:<nuxt-link exact to="/">Playfair</nuxt-link> 这是因为有很多路由都匹配 `/` 目录,实际上,所有的路由都匹配。因此,如果我们指定 exact,Nuxt 将知道我们只指的是索引页面。

更多资源

如果您想了解更多关于 Nuxt 的信息,他们的文档 写得很好,并且有很多示例可以帮助您入门。如果您想了解更多关于 Vue 的信息,我刚刚在 Frontend Masters 上开设了一门课程,所有课程材料都在这里开源,或者您可以查看我们的 Vue 指南,或者您可以访问 Vue 文档,它们写得非常棒。祝您编程愉快!