【服务端渲染】NuxtJS基础

Nuxt.js 的基本介绍

Nuxt.js 是什么

Nuxt.js 是一个基于 Vue.js 的服务端渲染应用框架,它可以帮我们轻松的实现同构应用。

通过对客户端/服务端基础架构的抽象组织,Nuxt.js 主要关注的是应用的 UI渲染

我们的目标是创建一个灵活的应用框架,你可以基于它初始化新项目的基础结构代码,或者在已有 Node.js 项目中使用 Nuxt.js。

Nuxt.js 预设了利用 Vue.js 开发服务端渲染的应用所需要的各种配置。

除此之外,我们还提供了一种命令叫:nuxt generate,为基于 Vue.js 的应用提供生成对应的静态站点的功能。

我们相信这个命令所提供的功能,是向开发集成各种微服务(Microservices)的 Web 应用迈开的新一 步。

作为框架,Nuxt.js 为 客户端/服务端 这种典型的应用架构模式提供了许多有用的特性,例如异步数据 加载、中间件支持、布局支持等非常实用的功能。

基本特性

  • 基于 Vue.js
    • Vue、Vue Router、Vuex、Vue SSR
  • 自动代码分层
  • 服务端渲染
  • 强大的路由功能,支持异步数据
  • 静态文件服务
  • ES2015+ 语法支持
  • 打包和压缩 JS 和 CSS
  • HTML 头部标签管理
  • 本地开发支持热加载
  • 集成 ESLint
  • 支持各种样式预处理器: SASS、LESS、 Stylus 等等
  • 支持 HTTP/2 推送

Nuxt.js 框架是如何运作的

【服务端渲染】NuxtJS基础
Nuxt.js 集成了以下组件/框架,用于开发完整而强大的 Web 应用:

  • Vue.js
  • Vue Router
  • Vuex
  • Vue Server Renderer

压缩并 gzip 后,总代码大小为:57kb(如果使用了 Vuex 特性的话为 60kb)。

另外,Nuxt.js 使用 Webpackvue-loaderbabel-loader 来处理代码的自动化构建工作(如打包、 代码分层、压缩等等)。

Nuxt.js 的使用方式

  • 初始项目
  • 已有的 Node.js 服务端项目
    • 直接把 Nuxt 当作一个中间件集成到 Node Web Server 中
  • 现有的 Vue.js 项目
    • 非常熟悉 Nuxt.js
    • 至少百分之十的代码改动

创建项目

官方文档:https://zh.nuxtjs.org/docs/2.x/get-started/installation

Nuxt 提供了两种方式用来创建项目:

  • 使用 create-nuxt-app 脚手架工具
  • 手动创建项目

手动创建项目

项目准备工作

  • 在 cmd 命令行,进行如下操作:

      # 创建示例项目 
      mkdir 01-nuxtjs-demo 
      # 进入示例项目目录中 
      cd 01-nuxtjs-demo  
      # 初始化 package.json 文件 
      npm init -y 
      # 安装 nuxt 
      npm innstall nuxt --save
    
  • package.json 文件的 scripts 中新增:

      {
          "scripts": {
              "dev": "nuxt"
          }
      }
    

    上面的配置使得我们可以通过运行 npm run dev 来运行 nuxt。

创建页面及启动项目

  • 创建 pages 目录,用来存放视图页面:

      mkdir pages 
    

    pages 是固定写法,不可更改

  • 创建页面 pages/index.vue

      <template> 
          <h1>Hello world!</h1> 
      </template> 
    
  • 运行命令,启动项目:

      npm run dev 
      # yarn dev
    

现在我们的应用运行在 http://localhost:3000 上运行。

注意:Nuxt.js 会监听 pages 目录中的文件更改,因此在添加新页面时无需重新启动应用程序。

Nuxt 路由

Nuxt.js 会依据 pages 目录中的所有 *.vue 文件生成应用的路由配置。

基础路由

  • 假设 pages 的目录结构如下:

    pages/ 
    --| user/ 
    -----| index.vue 
    -----| one.vue 
    --| index.vue
    

目录结果,如图所示:

【服务端渲染】NuxtJS基础

  • 那么,Nuxt.js 自动生成的路由配置如下:

    router: { 
        routes: [ 
            { 
                name: 'index', 
                path: '/', 
                component: 'pages/index.vue' 
            }, 
            { 
                name: 'user', 
                path: '/user', 
                component: 'pages/user/index.vue' 
            }, 
            { 
                name: 'user-one', 
                path: '/user/one', 
                component: 'pages/user/one.vue' 
            } 
        ] 
    } 
    
  • 此处的 user 目录名称,就是 路由名称,浏览器访问地址为:http://localhost:3000/user,即默认访问 pages/user/index.vue 页面

    【服务端渲染】NuxtJS基础

  • pages/user/one.vue,访问地址为:http://localhost:3000/user/one

    【服务端渲染】NuxtJS基础

路由导航

  • a 标签

    • 它会刷新整个页面,不推荐使用
      <!-- a 链接,刷新导航,走服务端渲染 -->
      <a href="/">首页</a>
    
  • 组件

      <!-- router-link 导航链接组件 -->
      <router-link to="/">首页</router-link>
      
      <!-- nuxt-link 导航链接组件 -->
      <nuxt-link to="/">首页</nuxt-link>
    
  • 编程式导航

      <!-- 编程式导航 -->
      <button @click="onClick">首页</button>
    
      methods: {
          onClick () {
              this.$router.push('/')
          }
      }
    

动态路由

在 Nuxt.js 里面定义带参数的动态路由,需要创建对应的以 下划线作为前缀 的 Vue 文件 或 目录。

  • 以下目录结构:

      pages/ 
      --| _slug/ 
      -----| comments.vue 
      -----| index.vue 
      --| users/ 
      -----| _id.vue 
      --| index.vue 
    

    目录结果,如图所示:

    【服务端渲染】NuxtJS基础

    注意:

    ​ 动态路由的文件是以 _ 作为前缀的,不可以省略

  • Nuxt.js 生成对应的路由配置表为:

      router: { 
          routes: [ 
              { 
                  name: 'index', 
                  path: '/', 
                  component: 'pages/index.vue' 
              }, 
              { 
                  name: 'users-id', 
                  path: '/users/:id?', 
                  component: 'pages/users/_id.vue' 
              }, 
              { 
                  name: 'slug', 
                  path: '/:slug', 
                  component: 'pages/_slug/index.vue'
              }, 
              { 
                  name: 'slug-comments', 
                  path: '/:slug/comments', 
                  component: 'pages/_slug/comments.vue' 
              } 
          ] 
      } 
    

    你会发现名称为 users-id 的路由路径带有 :id? 参数,表示该路由是可选的。如果你想将它设置为必选的路由,需要在 users/_id 目录内创建一个 index.vue 文件。

  • pages/users/_id.vue,代码示例如下:

      <div>
          <h1>User Page</h1>
          <p>{{ $route.params.id }}</p>
      </div>
    
  • 浏览器访问地址为:http://localhost:3000/users/2,其中后面的 2 代表动态路由,可以是任何值,也可以不输入,不输入时,默认访问 pages/users/index.vue

    【服务端渲染】NuxtJS基础

嵌套路由

  • Vue Router 嵌套路由

  • Nuxt.js 嵌套路由

    Warning: 别忘了在父组件( .vue文件) 内增加 <nuxt-child />,用于显示子视图内容。

  • 假设文件目录结构,如图所示:

      pages/ 
      --| users/ 
      -----| _id.vue 
      -----| index.vue 
      --| users.vue 
    

    目录结构,如图所示:

    【服务端渲染】NuxtJS基础

  • Nuxt.js 自动生成的路由配置如下:

      router: { 
          routes: [ 
              { 
                  path: '/users', 
                  component: 'pages/users.vue', 
                  children: [ 
                      { 
                          path: '', 
                          component: 'pages/users/index.vue', name: 'users' 
                      }, 
                      { 
                          path: ':id', 
                          component: 'pages/users/_id.vue', name: 'users-id' 
                      } 
                  ] 
              } 
          ] 
      } 
    
  • pages/users.vue中,书写子路由出口,代码示例如下:

      <!-- 子路由出口 -->
      <nuxt-child />
    
  • 浏览器访问地址:http://localhost:3000/users,默认访问 pages/users/index.vue

    【服务端渲染】NuxtJS基础

路由配置

base

应用程序的基URL。例如,如果整个单页应用程序在/app/,则base应使用该值'/app/' .

  • nuxt.config.js 文件中进行配置,代码示例如下:

       module.exports = {
           router: {
              base: '/app'
           }
       }
    
  • 重启项目成功后,会给出以下提示:

    【服务端渲染】NuxtJS基础

  • base设置后,Nuxt.js 也将添加到文档头中<base href="{{ router.base }}"/> .

    【服务端渲染】NuxtJS基础

extendRoutes

扩展Nuxt.js创建的路由。

  • nuxt.config.js

      module.exports = {
          router: {
              // routes: 一个数组,路由配置表
              // resolve:解析路由组件路径
              extendRoutes(routes, resolve) { // 自定义路由表
                  routes.push({
                      name: '/hello',
                      path: 'hello',
                      component: resolve(__dirname, 'pages/user/about.vue')
                  })
              }
          }
      }
    
  • 如果要对路线进行排序,可以使用sortRoutes(routes) 函数:

      import { sortRoutes } from '@nuxt/utils'
      module.exports = {
          router: {
              extendRoutes(routes, resolve) {
                  // Add some routes here ...
      
                  // and then sort them
                  sortRoutes(routes)
              }
          }
      }
    
  • 添加使用命名视图的管线时,不要忘记添加相应的chunkNames已命名的组件 .

      module.exports = {
          router: {
              extendRoutes(routes, resolve) {
                  routes.push({
                      path: '/users/:id',
                      components: {
                          default: resolve(__dirname, 'pages/users'), // or routes[index].component
                          modal: resolve(__dirname, 'components/modal.vue')
                      },
                      chunkNames: {
                          modal: 'components/modal'
                      }
                  })
              }
          }
      }
    

视 图

【服务端渲染】NuxtJS基础

模板


app模板用于为Nuxt.js应用程序创建文档的实际HTML框架,该应用程序为头部和主体注入内容以及变量。此文件是自动为您创建的,通常很少需要修改。通过创建一个app.html项目的源目录中的文件,默认情况下是根目录。

  • Nuxt.js使用的默认模板是:app.html

      <!DOCTYPE html>
      <html {{ HTML_ATTRS }}>
          <head {{ HEAD_ATTRS }}>
              {{ HEAD }}
          </head>
          <body {{ BODY_ATTRS }}>
              <!-- 渲染的内容最终会注入到这里 -->
              {{ APP }}
          </body>
      </html>
    
  • 使用自定义应用程序模板的一个用例是为IE添加条件CSS类:

      <!DOCTYPE html>
      <!--[if IE 9]><html class="lt-ie9 ie9" {{ HTML_ATTRS }}><![endif]-->
      <!--[if (gt IE 9)|!(IE)]><!--><html {{ HTML_ATTRS }}><!--<![endif]-->
        <head {{ HEAD_ATTRS }}>
          {{ HEAD }}
        </head>
        <body {{ BODY_ATTRS }}>
          {{ APP }}
        </body>
      </html>
    

    而您可以在app.html,建议使用nuxt.config.js来完成这些任务!

布局 Layout


当你想改变你的Nuxt.js应用程序的外观时,布局是一个很好的帮助。例如,您希望包含一个侧边栏或具有不同的移动和桌面布局。

默认布局

可以通过 添加 layouts/default.vue 文件。这将用于所有未指定布局的页面。您只需要在布局中包含<Nuxt />呈现页面组件的组件

  • layouts/default.vue

      <template>
          <!-- 页面出口,类似子路由出口 -->
          <Nuxt />
      </template>
    

自定义布局

可以通过添加.vue文件到 layouts 目录。为了使用自定义布局,您需要设置 布局 属性,该属性位于要使用该布局的页面组件中。该值将是您创建的自定义布局的名称。

  • 要创建博客布局,请添加blog.vue文件到布局目录布局/blog.vue :

      <template>
          <div>
              <div>My blog navigation bar here</div>
              <Nuxt />
          </div>
      </template>
    

    当创建一个实际包含页面组件的布局时,要确保添加

  • 然后,我们在希望使用布局的页面中使用值为**“blog”** 的 layout 属性。

      <template>
          <!-- Your template -->
      </template>
      <script>
          export default {
              layout: 'blog'
              // page component definitions
          }
      </script>
    

    如果不在页面中添加布局属性,例如。layout: 'blog',然后默认值 .vue 将使用布局

错误页面

  • 错误页是页面组件 ,它总是在发生错误时显示(服务器端呈现时不会发生这种情况)。

    虽然此文件位于layouts文件夹,但它应该被视为一个页面。

  • 如上所述,这个布局是特殊的,不应该包括 <Nuxt/> 组件在其模板中。必须将此布局视为发生错误时显示的组件( four hundred and four500 等等)。与其他页面组件类似,也可以按常规方式为错误页设置自定义布局。

  • 通过添加 layouts/error.vue 文件:

      <template>
          <div>
              <h1 v-if="error.statusCode === 404">Page not found</h1>
              <h1 v-else>An error occurred</h1>
              <NuxtLink to="/">Home page</NuxtLink>
          </div>
      </template>
      
      <script>
          export default {
              props: ['error'],
              layout: 'error' // you can set a custom layout for the error page
          }
      </script>
    

异步数据 – asyncData 方法

Nuxt.js 扩展了 Vue.js,增加了一个叫* asyncData *的方法,使得我们可以在设置组件的数据之前能 异步获取或处理数据。

  • https://zh.nuxtjs.org/docs/2.x/features/data-fetching/#async-data

  • 基本用法

    • pages/index.vue
      <template>
          <div id="app">
              <h1>{{ title }}</h1>
              <nuxt-link to="about">About</nuxt-link>
          </div>
      </template>
      
      <script>
          import axios from 'axios'
          export default {
              name: 'HomePage',
              // 当你想要动态页面内容,有利于 SEO 或者是 提升首屏渲染速度的时候,就在 asyncData 中发请求获取数据
              async asyncData () {
                  console.log('asyncData');
                  console.log(this); // undefined
                  // 首屏渲染
                  const res = await axios({
                      method: 'GET',
                      url: 'http://localhost:3000/data.json'
                  })
                  return res.data
              },
              // 如果是非异步数据或者普通数据,则正常的初始化到 data 中即可
              data () {
                  return {
                      foo: 'bar'
                  }
              }
          }
      </script>
    
    • 它会将 asyncData 返回的数据融合组件 data 方法返回数据一并给组件

    【服务端渲染】NuxtJS基础

    • 调用时机:服务端渲染期间和客户端路由更新之前

注意事项

  • 只能在页面组件中使用,非页面组件(子组件…)中使用会报错

    • components/foo.vue
      <template>
        <div>
            <h1>FooPage</h1>
            <p>{{ foo }}</p>
        </div>
      </template>
      <script>
        export default {
            name: 'FooPage',
        	async asyncData () {
          		return {
             		foo: 'bar'
        		}
          	}
        }
      </script>
    
    • pages/index.vue
      <template>
      	  <div id="app">
        	  <foo />
          </div>
      </template>
      <script>
      	  import Foo from '@/components/Foo'
          export default {
              name: 'HomePage',
              components: {
           		  Foo
           	  }
          }
       </script>
    

    此时,会报出如下错误:
    【服务端渲染】NuxtJS基础

  • 解决方式,利用父组件向子组件传递数据的方式:

    • components/foo.vue
      export default {
          name: 'FooPage',
          props: ["posts"]
          // async asyncData () {
          //     return {
          //         foo: 'bar'
          //     }
          // }
      }
    
    • pages/index.vue
      <foo :posts="posts" />
    
  • 没有 this,因为它是在组件初始化之前被调用的

上下文对象

  • https://zh.nuxtjs.org/docs/2.x/internals-glossary/context/

  • 这个context提供从 Nuxt 到 Vue 组件的其他对象/参数,并可用于特殊的Nuxt生命周期区域,如asyncData ,fetch ,plugins ,middlewarenuxtServerInit .

    这里指的是“我们不要混淆上下文”context对象在中可用Vuex Actions. 这两者毫无关联

  • cintext 上下文对象,包含内容,如下所示:

      function (context) {
          // Universal keys
          const {
              app,
              store,
              route,
              params,
              query,
              env,
              isDev,
              isHMR,
              redirect,
              error,
              $config
          } = context
          // Server-side
          if (process.server) {
              const { req, res, beforeNuxtRender } = context
          }
          // Client-side
          if (process.client) {
              const { from, nuxtState } = context
          }
      }
    docs/2.x/directory-structure/store#the-nuxtserverinit-action) .
    
上一篇:Nuxt.js学习笔记


下一篇:nuxt中使用Vuex