Nuxt.js 学习

Nuxt.js 学习

在学习Nuxt.js之前、我们要知道什么是客户端渲染(SPA)服务端渲染(SSR)

客户端渲染和服务端渲染

  • 客户端渲染 (SPA:single page application): 用户通过地址栏或者链接标签进入一个新的链接后,向服务器发出请求服务器直接根据链接返回一个html页面(没有数据),页面中的数据渲染则是由页面中的ajax完成ajax再次向服务器发出请求数据的请求,然后对页面进行渲染

    优点:

    1. 前后端分离,开发效率高。

    2. 用户体验更好,我们将网站做成SPA(单页面应用)或者部分内容做成SPA,当用户点击时,不会形成频繁的跳转。

    缺点:

    1. 前端响应速度慢,特别是首屏,这样用户是受不了的。

    2. 不利于SEO优化,因为爬虫不认识SPA,所以它只是记录了一个页面。

  • 服务端渲染 (SSR:server side rendering): 用户通过地址栏或者链接进入一个服务器所监听的服务器的路径,服务器则根据该路径返回一个页面(有数据),页面的数据渲染在服务器内由服务器完成,客户端只需要发送一次请求不用ajax

    优点:

    1. 尽量不占用前端的资源,前端这块耗时少,速度快。
    2. 有利于SEO优化,因为在后端有完整的html页面,所以爬虫更容易爬取信息。

    缺点:

    1. 不利于前后端分离,开发的效率降低了。
    2. 对html的解析,对前端来说加快了速度,但是加大了服务器的压力。

Vue 服务端渲染

官网: https://ssr.vuejs.org/zh/

通过npm init初始化一个项目

npm 安装

npm install vue vue-server-renderer --save

渲染一个 Vue 实例

index.js

// 第 1 步:创建一个 Vue 实例
const Vue = require('vue')
const app = new Vue({
    template: `
{{ message }}
`
, data: { message: "Hello world" } }) // 第 2 步:创建一个 renderer const renderer = require('vue-server-renderer').createRenderer() // 在 2.5.0+,如果没有传入回调函数,则会返回 Promise: renderer.renderToString(app).then(html => { console.log(html) }).catch(err => { console.error(err) })

通过node index.js

可以看到、直接将template中的模板渲染成了html

Hello world
元素

与服务器集成

index.js

const Vue = require('vue')
const server = require('express')()
const renderer = require('vue-server-renderer').createRenderer()

server.get('*', (req, res) => {
    const app = new Vue({
        data: {
            message: "你好、世界!"
        },
        template: `
欢迎访问 {{ message }}
`
}) renderer.renderToString(app, (err, html) => { if (err) { res.status(500).end('Internal Server Error') return } res.setHeader('Content-type', 'text/html;charset=utf-8'); res.end(` Hello ${html} `) }) }) server.listen(8080)

查看源代码我们可以看的、页面已经渲染成了HTML标签

Nuxt.js

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

Nuxt.js 是什么?

官网: https://zh.nuxtjs.org/

Nuxt.js 是一个基于 Vue.js 的通用应用框架。

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

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

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

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

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

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

安装

Nuxt.js 团队创建了脚手架工具 create-nuxt-app

npx create-nuxt-app <项目名>

解释一下npx

http://www.ruanyifeng.com/blog/2019/02/npx.html

这个是在 npmv5.2.0引入的一条命令(查看),引入这个命令的目的是为了提升开发者使用包内提供的命令行工具的体验。

  • 可以通过npx 调用项目安装的模块

    # 项目的根目录下执行
    $ node-modules/.bin/mocha --version
    
    # npx 调用
    $ npx mocha --version
    
  • create-nuxt-app这个模块是全局安装,npx 可以运行它,而且不进行全局安装。npx 将create-nuxt-app下载到一个临时目录,使用以后再删除。所以,以后再次执行上面的命令,会重新下载create-nuxt-app

npx命令找包顺序:先自动查找当前依赖包中的可执行文件,如果找不到,就会去 PATH 里找。如果依然找不到,就会帮你临时安装,执行完后再删除包。

Nuxt.js 学习_第1张图片

它会让你进行一些选择:

  1. 项目名称Project name: 直接回车

  2. 程序语言Programming language: (Use arrow keys): JavaScript和TypeScript 、选择JavaScript

  3. 包管理工具Package manager: (Use arrow keys): Yarn和NPM 、选择NPM

  4. UI框架UI framework: (Use arrow keys):None (无) Bootstrap Vuetify BulmaTailwind Element UI Ant Design Vue Buefy iView Tachyons

  5. 模块Nuxt.js modules: Axios和Progressive Web App (PWA)和Content 选择Axios

  6. 在保存时代码规范和错误检查您的代码Linting tools: ESLint、Prettier、Lint staged files、StyleLint

  7. 测试框架Testing framework: None Jest AVA WebdriverIO

  8. 渲染模式Rendering mode

    Universal (SSR / SSG)
    Single Page App

  9. Deployment target

    Server (Node.js hosting)

    Static (Static/JAMStack hosting)

  10. Development tools:

    jsconfig.json (Recommended for VS Code if you’re not using typescript)
    Semantic Pull Requests

当运行完时,它将安装所有依赖项,因此下一步是启动项目:

$ cd <project-name>
$ npm run dev

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

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

目录结构

├── assets    		资源目录                       
├── components      组件目录                    
│   └── Logo.vue                   
├── layouts      	布局目录                        
│   └── default.vue                   
├── middleware		中间件目录
├── pages 			页面目录
│   └── index.vue
├── plugins			插件目录
├── static			静态文件目录
├── store			Vuex 状态树文件
├── .editorconfig
├── .eslintrc.js
├── .gitgnore
├── nuxt.config.js 个性化配置
└── package.json        
  • 资源目录 assets 用于组织未编译的静态资源如 LESSSASSJavaScript

  • 组件目录 components 用于组织应用的 Vue.js 组件。Nuxt.js 不会扩展增强该目录下 Vue.js 组件,即这些组件不会像页面组件那样有 asyncData 方法的特性。

  • 布局目录 layouts 用于组织应用的布局组件。

  • middleware 目录用于存放应用的中间件。

  • 页面目录 pages 用于组织应用的路由及视图。Nuxt.js 框架读取该目录下所有的 .vue 文件并自动生成对应的路由配置。

  • 插件目录 plugins 用于组织那些需要在 根vue.js应用 实例化之前需要运行的 Javascript 插件。

  • 静态文件目录 static 用于存放应用的静态文件,此类文件不会被 Nuxt.js 调用 Webpack 进行构建编译处理。服务器启动的时候,该目录下的文件会映射至应用的根路径 / 下。

    举个例子: /static/robots.txt 映射至 /robots.txt

  • store 目录用于组织应用的 Vuex 状态树 文件。 Nuxt.js 框架集成了 Vuex 状态树 的相关功能配置,在 store 目录下创建一个 index.js 文件可激活这些配置。

  • nuxt.config.js 文件用于组织 Nuxt.js 应用的个性化配置,以便覆盖默认配置。

  • package.json 文件用于描述应用的依赖关系和对外暴露的脚本接口。

别名 目录
~@ srcDir
~~@@ rootDir

默认情况下,srcDirrootDir 相同。

提示: 在您的 vue 模板中, 如果你需要引入 assets 或者 static 目录, 使用 ~/assets/your_image.png~/static/your_image.png方式。

路由配置

Nuxt.js 会根据 pages 目录下的目录结构自动生成 vue-router 模块的路由配置

类似Vue-router中的router-link、在页面之间跳转使用nuxt-link 标签

例如:

<nuxt-link to="/user">进入个人页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'
    }
  ]
}

嵌套路由

当然、你还可以使用另一种目录结构: user.vue、user目录、user目录下的one.vue

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

但是你要访问user下的one.vue: /user/one 需要在user.vue 添加


<template>
  <div>
      我是用户页
    <nuxt-child />
  div>
template>
动态路由

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

例如:

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

这样我们就可以在index.vue进行操作

<template>
  <div>
      这里是index页面
      <ul>
        <li v-for="(item,index) in dataList" :key="index" @click="handleClick(item)">{{ item }}li>
      ul>
  div>
template>

<script>
export default {
  data(){
    return{
      dataList: ["info","data","now","time"]
    }
  },
  methods:{
    handleClick(data){
      this.$router.push("/detail/"+data)
    }
  }
}
script>

_id.vue 注意: 通过$route.params取得的参数名为以下划线作为前缀的内容 、例: _id.vue、获取就是通过 $route.params.id 传入的参数

<template>
    <div>
        {{ $route.params.id }}
    div>
template>

<script>
export default {

}
script>

<style>

style>

参数检验

判断参数是否合法来返回页面 validate

简单判断一下以数字开头、validate返回为假时跳转错误页面

<template>
  <div>
    <p>我的id: {{ $route.params.me }}p>
  div>
template>

<script>
import axios from "axios";
export default {
  layout: "me",
  validate({params}){
    return /^\d+/.test(params.me)
  }
};
script>

<style>
style>

我们可以在.nuxt目录下router.js看的路由结构

视图

视图的整体布局图如下所示:

模板

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

默认模板:


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

例如:



<html {{ HTML_ATTRS }}>
  <head {{ HEAD_ATTRS }}>
    {{ HEAD }}
  head>
  <body {{ BODY_ATTRS }}>
      我是app.html里的内容
    {{ APP }}
  body>
html>

Nuxt.js 学习_第2张图片

布局

Nuxt.js 允许你扩展默认的布局,或在 layout 目录下创建自定义的布局

默认布局

vue-router中、使用router-view用来显示页面

在nuxt、布局文件(layouts)中添加 组件用于显示页面的主体内容。

默认布局default.vue源码如下

<template>
  <nuxt />
template>
自定义布局

如果不想使用nuxt的默认布局页面、可以使用自定义布局:

  • layouts目录下创建布局文件xxx.vue 、并且要有 否则只显示xxx.vue里的内容
  • 在需要的使用的页面中添加layout: xxx(不需要.vue)

例如:

假设我们要创建一个 博客布局 并将其保存到layouts/blog.vue:

<template>
  <div>
    <div>我的博客导航栏在这里div>
    <nuxt />
  div>
template>

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

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

更多有关 layout 属性信息: API 页面 布局

错误页面

你可以通过编辑 layouts/error.vue 文件来定制化错误页面.

这个布局文件不需要包含 标签。你可以把这个布局文件当成是显示应用错误(404,500 等)的组件。

官方提供的一个简单的页面 layouts/error.vue:

<template>
  <div class="container">
    <h1 v-if="error.statusCode === 404">页面不存在h1>
    <h1 v-else>应用发生错误异常h1>
    <nuxt-link to="/">首 页nuxt-link>
  div>
template>

<script>
  export default {
    props: ['error'],
    layout: 'blog' // 你可以为错误页面指定自定义的布局
  }
script>
页面

页面组件实际上是 Vue 组件,只不过 Nuxt.js 为这些组件添加了一些特殊的配置项(对应 Nuxt.js 提供的功能特性)以便你能快速开发通用应用。

Nuxt.js提供的特殊配置项如下表所示:

属性名 描述
asyncData 最重要的一个键, 支持 异步数据处理,另外该方法的第一个参数为当前页面组件的 上下文对象。
fetch asyncData 方法类似,用于在渲染页面之前获取数据填充应用的状态树(store)。不同的是 fetch 方法不会设置组件的数据。详情请参考 关于 fetch 方法的文档。
head 配置当前页面的 Meta 标签, 详情参考 页面头部配置 API。
layout 指定当前页面使用的布局(layouts 根目录下的布局文件)。详情请参考 关于 布局 的文档。
loading 如果设置为false,则阻止页面自动调用this.$nuxt.$loading.finish()this.$nuxt.$loading.start(),您可以手动控制它,请看例子,仅适用于在 nuxt.config.js 中设置loading的情况下。请参考API 配置 loading 文档。
transition 指定页面切换的过渡动效, 详情请参考 页面过渡动效。
scrollToTop 布尔值,默认: false。 用于判定渲染页面前是否需要将当前页面滚动至顶部。这个配置用于 嵌套路由的应用场景。
validate 校验方法用于校验 动态路由的参数。
middleware 指定页面的中间件,中间件会在页面渲染之前被调用, 请参考 路由中间件。

关于页面配置项的详细信息,请参考 页面 API。

HTML头部

Nuxt.js 使用了 vue-meta 更新应用的 头部标签(Head) and html 属性

Nuxt.js 使用以下参数配置 vue-meta:

{
  keyName: 'head', // 设置 meta 信息的组件对象的字段,vue-meta 会根据这 key 值获取 meta 信息
  attribute: 'n-head', // vue-meta 在监听标签时所添加的属性名
  ssrAttribute: 'n-head-ssr', // 让 vue-meta 获知 meta 信息已完成服务端渲染的属性名
  tagIDKeyName: 'hid' // 让 vue-meta 用来决定是否覆盖还是追加 tag 的属性名
}

重定向

如果我们想访问http://localhost:3000/想跳转到http://localhost:3000/user 、配置完记得重新启动

方法1:nuxt.config.js配置

router:{
    extendRoutes(routes){
        routes.push({
            path:"/",
            redirect: "/user"
        })
    }
}

这样访问根目录就会重定向到/user

但是我发现一个问题:如果 根目录/也就是index.vue 存在的话、通过路由跳转不起作用、解决办法就是删除index.vue、或者使用中间件的方法

方法2:middleware中间件

middleware下创建redirect.js

export default function({isHMR,app,store,route,params,error,redirect}){
    if(isHMR) return
    // 页面均放在_lang文件夹下,即lang为动态路由参数
    /*if (!params.lang) {  //此写法会出现路由重定向次数过多的问题
        return redirect('/' + defaultLocale + '' + route.fullPath)
    }
    */
    if(route.fullPath == "/home"){
        return redirect('/home/catagory')
    }
}

修改nuxt.config.js 添加middleware属性、对应的值为middleware目录下的文件名

router: {
    middleware:'redirect',
  }

方法3: 组件中

asyncData中有redirect属性

<template>
  <div>div>
template>

<script>
export default {
  asyncData({ redirect }) {
    redirect('/user')
  }
}
script>

异步数据

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

asyncData 方法
  • asyncData方法会在组件(限于页面组件)每次加载之前被调用。 简单来说就是在页面直接切换客户端会调用改方法
  • 可以在服务端或路由更新之前被调用。简单来说就是直接对页面进行刷新时服务端调用并且渲染数据
  • asyncData 返回的数据融合组件 data 方法返回的数据一并返回给当前组件。
  • 必须将数据用return返回出去、否则无法获取数据

注意:由于asyncData方法是在组件 初始化 前被调用的,所以在方法内是没有办法通过 this 来引用组件的实例对象。所以需要用过 return 返回对象 、如 return { dataList : res.data.data.films }

举个例子:

1.axios 方法

pages/index.vue通过直接刷新页面、客户端控制台不会打印数据(最新版好像也会打印)、而是在服务端打印

<template>
  <div>
    Hello world
    <ul>
      <li v-for="(item,index) in dataList" :key="index" @click="handleClick(item.filmId)">
        <img :src="item.poster" alt="">
        {{ item.name }}
        li>
    ul>
  div>
template>

<script>
import axios from "axios";

export default {
  data() {
    return {
      dataList: ["info", "data", "now", "time"],
    };
  },
  methods: {
    handleClick(data) {
      this.$router.push("/me/" + data);
    },
  },
  asyncData() {
    return axios({
      url:
        "https://m.maizuo.com/gateway?cityId=110100&pageNum=1&pageSize=10&type=1&k=7662183",
      headers: {
        "X-Client-Info":'{"a":"3000","ch":"1002","v":"5.0.4","e":"1597199484263152646225921","bc":"110100"}',
        "X-Host": "mall.film-ticket.film.list",
      },
    }).then((res) => {
      console.log(res.data);  
      return {
        // 这里需要直接返回对象  
        dataList : res.data.data.films
      }
    });
  },
};
script>

<style>
style>

Nuxt.js 学习_第3张图片

只有在其他页面切换回当前页、才会在客户端控制台打印数据

2.aysnc

script>
export default {
  data() {
    return {
      dataList: null
    };
  },
  async asyncData() {
	let {data} = await axios({ url: "https://m.maizuo.com/gatewaycityId=110100&pageNum=1&pageSize=10&type=1&k=7662183",headers: { "X-Client-Info":'{"a":"3000","ch":"1002","v":"5.0.4","e":"1597199484263152646225921","bc":"110100"}',"X-Host": "mall.film-ticket.film.list",
      },
    })
    return { dataList : data.data.films}
  }
};
script>
asyncData 参数

通过直接打印asyncData中的参数可以看到:

Nuxt.js 学习_第4张图片

里面的参数也就是上下文对象

上下文对象

可通过 API context 来了解该对象的所有属性和方法。

context 变量的可用属性一览:

属性字段 类型 可用 描述
app Vue 根实例 客户端 & 服务端 包含所有插件的 Vue 根实例。例如:在使用 axios 的时候,你想获取 $axios 可以直接通过 context.app.$axios 来获取
isClient Boolean 客户端 & 服务端 是否来自客户端渲染(废弃。请使用 process.client
isServer Boolean 客户端 & 服务端 是否来自服务端渲染(废弃。请使用 process.server
isStatic Boolean 客户端 & 服务端 是否来自 nuxt generate 静态化(预渲染)(废弃。请使用 process.static
isDev Boolean 客户端 & 服务端 是否是开发 dev 模式,在生产环境的数据缓存中用到
isHMR Boolean 客户端 & 服务端 是否是通过模块热替换 webpack hot module replacement (仅在客户端以 dev 模式)
route Vue Router 路由 客户端 & 服务端 Vue Router 路由实例
store Vuex 数据 客户端 & 服务端 Vuex.Store 实例。只有vuex 数据流存在相关配置时可用
env Object 客户端 & 服务端 nuxt.config.js 中配置的环境变量,见 环境变量 api
params Object 客户端 & 服务端 route.params 的别名
query Object 客户端 & 服务端 route.query 的别名
req http.Request 服务端 Node.js API 的 Request 对象。如果 Nuxt 以中间件形式使用的话,这个对象就根据你所使用的框架而定。nuxt generate 不可用
res http.Response 服务端 Node.js API 的 Response 对象。如果 Nuxt 以中间件形式使用的话,这个对象就根据你所使用的框架而定。nuxt generate 不可用
redirect Function 客户端 & 服务端 用这个方法重定向用户请求到另一个路由。状态码在服务端被使用,默认 302 redirect([status,] path [, query])
error Function 客户端 & 服务端 用这个方法展示错误页:error(params)params 参数应该包含 statusCodemessage 字段
nuxtState Object 客户端 Nuxt 状态,在使用 beforeNuxtRender 之前,用于客户端获取 Nuxt 状态,仅在 universal 模式下可用
beforeNuxtRender(fn) Function 服务端 使用此方法更新 __NUXT__ 在客户端呈现的变量,fn 调用 (可以是异步) { Components, nuxtState } ,参考 示例

反向代理

对于前端跨域问题、我们需要配置反向代理

需要安装

npm install --save @nuxtjs/proxy

nuxt.config.js中配置

例如: 猫眼电影 https://m.maoyan.com/ 的首页数据请求API https://m.maoyan.com/ajax/movieOnInfoList?token=

需要如下配置

modules: [
    '@nuxtjs/axios',
    '@nuxtjs/proxy'
],
proxy:{
    '/ajax':{
      target: "https://m.maoyan.com/",
      // changeOrigin默认是false:请求头中host仍然是浏览器发送过来的host    
      changeOrigin: true
    }
},    
axios: {
    proxy:true
},

page.vue

<template>
    <div>
        我是分类内容页面
    div>
template>

<script>
import axios from 'axios'
export default {
  asyncData(){
    return axios({
      url: '/ajax/movieOnInfoList?token='
    }).then(res=>{
      console.log(res.data);
    })
  }
}
script>

<style>

style>

但是如果直接进行刷新是请求 /ajax/movieOnInfoList?token= 服务器没有跨域、会404、所以需要判断一下是服务端还是客户端

通过process.server、返回true为服务端、接下来简单判断一下就行了

url: process.server ? 'https://m.maoyan.com/ajax/movieOnInfoList?token=' : '/ajax/movieOnInfoList?token='

路由动画

路由的动画效果,也叫作页面的更换效果。Nuxt.js提动两种方法为路由提动动画效果,一种是全局的,一种是针对单独页面制作。

全局路由动画

全局动画默认使用page进行设置,例如现在我们为每个页面都设置一个进入和退出时的渐隐渐现的效果。我们可以先在根目录的assets/css下建立一个normailze.css文件。

.page-enter-active,.page-leave-active{
    transition: opacity 2s;
}
.page-enter,.page-leave-active{
    opacity: 0;
}

编辑nuxt.config.js

css: ['~assets/css/normailze.css'],

但是只有使用的才有动画效果

单独设置页面动效

给一个页面单独设置特殊的效果时,我们只要在css里改变默认的page,然后在页面组件的配置中加入transition字段即可。例如,我们想给about页面加入一个字体放大然后缩小的效果

编辑assets/css/normailze.css test为自定义效果名

.test-enter-active,.test-leave-active{
    transition: all 2s;
    font-size: 12px;
}
.test-enter,.test-leave-active{
    opacity: 0;
    font-size: 40px;
}

在需要的组件中添加

<script>
export default {
    transition:'test'
}
script>

你可能感兴趣的:(前端,vue.js)