Vue.js 框架源码与进阶 - Nuxt.js 基础

一、NuxtJS 介绍

1.1 NuxtJS 是什么

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

  • 通过对客户端/服务端基础架构的抽象组织,Nuxt.js 主要关注的是应用的 UI 渲染
  • 我们的目标是创建一个灵活的应用框架,你可以基于它初始化新项目的基础结构代码,或者在已有 Node.js 项目中使用 Nuxt.js
  • Nuxt.js 预设了利用 Vue.js 开发服务端渲染的应用所需要的各种配置
  • 除此之外,我们还提供了一种命令叫: nuxt generate ,为基于 Vue.js 的应用提供生成对应的静态站点的功能
  • 我们相信这个命令所提供的功能,是向开发集成各种微服务(Microservices)的 Web 应用迈开的新一步
  • 作为框架,Nuxt.js 为 客户端/服务端 这种典型的应用架构模式提供了许多有用的特性,例如异步数据加载、中间件支持、布局支持等非常实用的功能

1.2 NuxtJS 特性

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

1.3 NuxtJS 框架是如何运作的

在这里插入图片描述

  • Nuxt.js 集成了以下组件/框架,用于开发完整而强大的 Web 应用:
    • Vue.js
    • Vue Router
    • Vuex
    • Vue Server Renderer
  • 压缩并 gzip 后,总代码大小为:57kb (如果使用了 Vuex 特性的话为 60kb)
  • 另外,Nuxt.js 使用 Webpackvue-loaderbabel-loader 来处理代码的自动化构建工作(如打包、代码分层、压缩等等)

1.4 NuxtJS 渲染流程

下图阐述了 Nuxt.js 应用一个完整的服务器请求到渲染(或用户通过 切换路由渲染页面)的流程:

在这里插入图片描述

1.5 NuxtJS 使用方式

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

二、初始化 NuxtJS

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

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

为了让大家有一个更好的学习效果,这里我们建议先通过手动创建的方式来学习 Nuxt,熟悉了 Nuxt 的基本能使用之后,我们会在后面的综合案例中学习如何使用 create-nuxt-app 创建项目

2.1 准备

# 初始化 package.json 文件
npm init -y

# 安装 nuxt
npm install nuxt
  • 在 package.json 文件的 scripts 中新增
"scripts": {
  "dev": "nuxt"
}

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

2.2 创建页面并启动项目

在这里插入图片描述

  • 创建 pages 目录
  • 创建我们的第一个页面 pages/index.vue
<template>
  <h1>Hello world!</h1>
</template>
  • 启动项目
npm run dev
或
yarn dev
  • 现在我们的应用运行在 http://localhost:3000 上运行

在这里插入图片描述

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

三、 Nuxt 中的路由

3.1 基础路由

  • 官方文档
  • Nuxt.js 会依据 pages 目录中的所有 *.vue 文件生成应用的路由配置
  • 要在页面之间使用路由,我们建议使用<nuxt-link> 标签
  • 假设 pages 的目录结构如下:
pages/
--| user/
-----| index.vue
-----| one.vue
--| index.vue
  • 那么,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'
    }
  ]
}

3.2 路由导航

<template>
  <div>
    <h1>About page</h1>
    <!-- a 链接,刷新导航,走服务端渲染 -->
    <h2>a 链接</h2>
    <a href="/">首页</a>

    <!-- nuxt-link 导航链接组件 -->
    <h2>router-link</h2>
    <nuxt-link to="/">首页</nuxt-link>

    <!-- 编程式导航 -->
    <h2>编程式导航</h2>
    <button @click="onClick">首页</button>
  </div>
</template>

<script>
export default {
  name: 'AboutPage',
  methods: {
    onClick () {
      this.$router.push('/')
    }
  }
}
</script>

3.3 动态路由

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

以下目录结构:

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

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'
    }
  ]
}

pages/user/_id.vue

<template>
  <div>
    <h1>User Pages</h1>
    <p>{{ $route.params.id }}</p>
  </div>
</template>

<script>
export default {
  name: "UserPage",
};
</script>

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

在这里插入图片描述

在这里插入图片描述

3.4 路由参数校验

pages/users/_id.vue

export default {
  validate({ params }) {
    // 必须是number类型
    return /^\d+$/.test(params.id)
  }
}

如果校验方法返回的值不为 true 或 Promise 中 resolve 解析为 false 或抛出 Error , Nuxt.js 将自动加载显示 404 错误页面或 500 错误页面。

3.5 嵌套路由


  • 你可以通过 vue-router 的子路由创建 Nuxt.js 应用的嵌套路由
  • 创建内嵌子路由,你需要添加一个 Vue 文件,同时添加一个与该文件同名的目录用来存放子视图组件。注意: 别忘了在父组件(.vue文件) 内增加 <nuxt-child/> 用于显示子视图内容

假设文件结构如:

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

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'
        }
      ]
    }
  ]
}

3.6 自定义路由配置

四、NuxtJS 视图

4.1 概述

在这里插入图片描述

  • 在 NuxtJS 中页面结构一般由三部分组成
    • 第一部分是最外层的文档页面,也就是单页面或者说服务端渲染的HTML页面
    • 在 HTML 页面里面包裹着 Layout 布局组件(可选),相当于所有页面的父路由
    • 再往里面是页面组件,每个页面组件有自己额外的成员方法,包括页面的子组件之类的可选内容

4.2 模板

  • 你可以定制化 Nuxt.js 默认的应用模板
  • 定制化默认的 html 模板,只需要在 src 文件夹下(默认是应用根目录)创建一个 app.html 的文件

默认模板为:

<!DOCTYPE html>
<html {{ HTML_ATTRS }}>
  <head {{ HEAD_ATTRS }}>
    {{ HEAD }}
  </head>
  <body {{ BODY_ATTRS }}>
    {{ APP }}
  </body>
</html>

可修改为:

<!DOCTYPE html>
<html {{ HTML_ATTRS }}>
  <head {{ HEAD_ATTRS }}>
    {{ HEAD }}
  </head>
  <body {{ BODY_ATTRS }}>
    <!-- 渲染的内容最终会注入到这里 -->
    <h1>app.html</h1>
    {{ APP }}
  </body>
</html>

4.3 布局

  • Nuxt.js 允许你扩展默认的布局,或在 layout 目录下创建自定义的布局
  • 可通过添加 layouts/default.vue 文件来扩展应用的默认布局

提示:别忘了在布局文件中添加 <nuxt/> 组件用于显示页面的主体内容。

默认布局的源码如下:

<template>
  <nuxt />
</template>

layouts/default.vue

<!-- 一旦使用,默认所有页面都会作用,不能取消,只能更改 -->
<template>
  <div>
    <h1>layouts/default.vue 组件</h1>
    <!-- 页面出口,类似于子路由出口 -->
    <nuxt />
  </div>
</template>

<script>
export default {
  name: 'LayoutDefault'
}
</script>

然后我们必须告诉页面 (即 pages/index.vue) 使用您的自定义布局:

<template>
  <h1>Hello world!</h1>
</template>

<script>
export default {
  name: 'HomePage',
  // 默认 default 可修改
  layout: 'default'
}
</script>

五、NuxtJS 异步数据

5.1 asyncData

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

  • 它会将 asyncData 返回的数据融合组件 data 方法返回的数据一并给组件
  • 调用时机:服务端渲染期间和客户端路由更新之前

static/data.json

{
  "posts": [
    {
      "id": 1,
      "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
      "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
    },
    {
      "id": 2,
      "title": "qui est esse",
      "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla"
    },
    {
      "id": 3,
      "title": "ea molestias quasi exercitationem repellat qui ipsa sit aut",
      "body": "et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et velit aut"
    },
    {
      "id": 4,
      "title": "eum et est occaecati",
      "body": "ullam et saepe reiciendis voluptatem adipisci\nsit amet autem assumenda provident rerum culpa\nquis hic commodi nesciunt rem tenetur doloremque ipsam iure\nquis sunt voluptatem rerum illo velit"
    },
    {
      "id": 5,
      "title": "nesciunt quas odio",
      "body": "repudiandae veniam quaerat sunt sed\nalias aut fugiat sit autem sed est\nvoluptatem omnis possimus esse voluptatibus quis\nest aut tenetur dolor neque"
    }
  ],
  "title": "测试用例"
}
  • NuxtJS 默认在 Web 服务中将数据暴露出来,可以直接通过 …/data.json 获取数据

在这里插入图片描述

  • 假设想在首页直接获取数据(服务端获取异步数据):
npm i axios

pages/index.vue

<template>
  <div>
    <h1>Hello world!</h1>
    <nuxt></nuxt>
  </div>
</template>
<script>
import axios from 'axios'

export default {
  name: 'HomePage',
  layout: 'default',
  async asyncData () {
    console.log('asyncData')
    console.log(this)
    const res = await axios({
      method: 'GET',
      url: 'http://localhost:3000/abc/data.json'
    })
    return res.data
  },
  data () {
    return {
      foo: 'bar'
    }
  }
}
</script>

asyncData 返回的数据融合组件 data 方法返回的数据一并给组件

注意:由于 asyncData 方法是在组件 初始化 前被调用的,所以在方法内是没有办法通过 this 来引用组件的实例对象

当你想要动态页面内容有利于 SEO ,或者是提升首屏渲染速度的时候,就在 asyncData 中发请求拿数据。如果是非异步数据或者普通数据,则正常的初始化到 data 中即可

服务端首屏渲染既能确保异步数据能在渲染到客户端之前已经被渲染好(提高首屏渲染速度,有利于SEO)。达到页面后又变成SPA客户端应用,同样可以被调用从而更新数据

5.2 上下文对象

六、NuxtJS 生命周期

在这里插入图片描述

七、Nuxt 项目发布部署流程

7.1 打包

{
  "scripts": {
    "dev": "nuxt",
    "build": "nuxt build",
    "start": "nuxt start"
  }
}
  • 执行打包命令,打包文件存储在.nuxt/dist
    • 建议将 .nuxt 加入 .npmignore.gitignore 文件中
npm run build
  • 启动打包项目
npm run start

7.2 最简单的部署方式

  • 配置 Host + Port

nuxt.config.js

server: {
// 此设置可监听所有的网卡地址
  host: '0.0.0.0', // 默认localhost
  port: 3000
}
  • 压缩发布包
    • .nuxt:Nuxt 打包生成的资源文件
    • static:项目静态资源
    • nuxt.config.js:提供给 Nuxt 服务
    • package.json:用于服务端第三方包的安装
    • package-lock.json:用于服务端第三方包的安装
  • 把发布包传到服务端
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

每天内卷一点点

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值