当前位置:   article > 正文

服务端渲染技术之Nuxt.js的详细使用_nuxt.js做服务端渲染

nuxt.js做服务端渲染

服务端渲染

服务端渲染又称SSR (Server Side Render)是在服务端完成页面的内容,而不是在客户端通过AJAX获取数据。

服务器端渲染优势主要在于:更好的 SEO,由于搜索引擎爬虫抓取工具可以直接查看完全渲染的页面。

使用服务器端渲染,可以获得更快的内容到达时间,无需等待所有的 JavaScript 都完成下载并执行,产生更好的用户体验。

Nuxt.js概述

Nuxt.js 是一个基于 Vue.js 的轻量级应用框架,可用来创建服务端渲染 (SSR) 应用,也可充当静态站点引擎生成静态站点应用,具有优雅的代码结构分层和热加载等特性。

Nuxt.js 预设了利用 Vue.js 开发服务端渲染的应用所需要的各种配置,为客户端/服务端 这种典型的应用架构模式提供了许多有用的特性,例如异步数据加载、中间件支持、布局支持等。

官网: https://nuxtjs.org/

中文网站:https://www.nuxtjs.cn/

Nuxt.js 应用一个完整的服务器请求到渲染(或用户通过 切换路由渲染页面)的流程:
在这里插入图片描述

一句话:为什么使用Nuxt.js?

对于有SEO需求的网页如果使用前端渲染技术去开发就不利于SEO,而Nuxt.js提供了服务
端渲染的解决方案,使用Nuxt.js则将有利于SEO。

创建Nuxt工程

Nuxt.js 团队创建了脚手架工具 create-nuxt-app,使用时需安装create-nuxt-app脚手架

npm install create-nuxt-app -g
  • 1

创建Nuxt项目

npx create-nuxt-app 项目名

在`NPM`版本5.2.0默认安装了`npx`,在命令行窗口输入`npm --version`可查看当前版本号
  • 1
  • 2
  • 3

输入项目名

Generating Nuxt.js project in nuxt
? Project name: nuxt_demo
  • 1
  • 2

选择JavaScript作为编程语言

? Programming language: (Use arrow keys)
> JavaScript
  TypeScript
  • 1
  • 2
  • 3

选择Npm作为包管理工具

? Package manager: (Use arrow keys)
   Yarn
>  Npm
  • 1
  • 2
  • 3

选择喜欢的 UI 框架

? UI framework: (Use arrow keys)
> None
  Ant Design Vue
  BalmUI
  Bootstrap Vue
  Buefy
  Bulma
  Chakra UI
  Element
  Framevuerk
  iView
  Tachyons
  Tailwind CSS
  Vuesax
  Vuetify.js
  Oruga
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

选择Axios作为Nuxt.js模块,需要通过按空格键才会选中期望值,此时括号中会出现星号,然后按下回车键进行确认即可。

? Nuxt.js modules: (Press <space> to select, <a> to toggle all, <i> to invert selection)
>( ) Axios - Promise based HTTP client
 ( ) Progressive Web App (PWA)
 ( ) Content - Git-based headless CMS

? Nuxt.js modules:
>(*) Axios - Promise based HTTP client
 ( ) Progressive Web App (PWA)
 ( ) Content - Git-based headless CMS
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

选择ESLint工具作为代码规范检查工具

? Linting tools: (Press <space> to select, <a> to toggle all, <i> to invert selection)
>( ) ESLint
 ( ) Prettier
 ( ) Lint staged files
 ( ) StyleLint
 ( ) Commitlint
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

选择测试框架

? Testing framework: (Use arrow keys)
> None
  Jest
  AVA
  WebdriverIO
  Nightwatch
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

选择渲染模式为SSR,SPA适合在客户端渲染

> Universal (SSR / SSG)
  Single Page App
  • 1
  • 2

启动项目

cd 项目名
npm run 项目名
  • 1
  • 2

应用现在运行在 http://localhost:3000 上运行。
在这里插入图片描述

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

目录结构

在这里插入图片描述

资源目录

资源目录assets 用于组织未编译的静态资源如 LESS、SASS 或 JavaScript。
  • 1

组件目录

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

布局目录

布局目录 layouts 用于组织应用的布局组件。
该目录名为Nuxt.js保留的,不可更改。
  • 1
  • 2

中间件目录

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

页面目录

页面目录 pages 用于组织应用的路由及视图。Nuxt.js 框架读取该目录下所有的 .vue 文件并自动生成对应的路由配置。
该目录名为Nuxt.js保留的,不可更改。
  • 1
  • 2

插件目录

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

静态文件目录

静态文件目录 static 用于存放应用的静态文件,此类文件不会被 Nuxt.js 调用 Webpack 进行构建编译处理。

服务器启动的时候,该目录下的文件会映射至应用的根路径 / 下。

举个例子: /static/logo.png 映射至 /logo.png

该目录名为Nuxt.js保留的,不可更改。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Store 目录

store 目录用于组织应用的 Vuex 状态树 文件。

Nuxt.js 框架集成了 Vuex 状态树 的相关功能配置,在 store 目录下创建一个 index.js 文件可激活这些配置。
 
该目录名为Nuxt.js保留的,不可更改。
  • 1
  • 2
  • 3
  • 4
  • 5

nuxt.config.js 文件

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

该文件名为Nuxt.js保留的,不可更改。
  • 1
  • 2
  • 3

package.json 文件

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

该文件不能被重命名。
  • 1
  • 2
  • 3

别名

别名目录
~@src目录 / srcDir
~~@@根目录 / rootDir
默认情况下,srcDir 和 rootDir 相同。

提示: vue 模板中, 如果需要引入 assets 或者 static 目录, 使用 ~/assets/your_image.png 和 ~/static/your_image.png方式。
  • 1
  • 2
  • 3

路由

基础路由

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

Nuxt.js根据pages的目录结构及页面名称定义规范来生成路由

要在页面之间使用路由,建议使用<nuxt-link> 标签。

<template>
  <nuxt-link to="/">首页</nuxt-link>
</template>
  • 1
  • 2
  • 3

假设 pages 的目录结构如下:

pages/
--| user/
-----| index.vue
-----| one.vue
--| index.vue
  • 1
  • 2
  • 3
  • 4
  • 5

那么,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'
    }
  ]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

index.vue

<template>
  <div>index.vue</div>
</template>

<script>
export default {
  name: "index"
}
</script>

<style scoped>

</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

one.vue

<template>
  <div>one.vue</div>
</template>

<script>
export default {
  name: "one"
}
</script>

<style scoped>

</style>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

进行测试:

http://localhost:3000/user在这里插入图片描述

http://localhost:3000/user/one
在这里插入图片描述

动态路由

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

以下目录结构:

pages/
--| _slug/
-----| comments.vue
-----| index.vue
--| users/
-----| _id.vue
--| index.vue
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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'
    }
  ]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

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

API Configuration generate

警告:generate 命令会忽略动态路由: API Configuration generate
  • 1
  • 2
  • 3

创建user.vue文件与user目录同一级

<template>
  <div>
    user.vue
    <nuxt-child/>
  </div>
</template>

<script>
export default {
  name: "user"
}
</script>

<style scoped>

</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

在user目录下创建_id.vue文件

<template>
  <div>
    参数id值:{{id}}
  </div>
</template>

<script>
export default {
  name: "_id",
  data(){
    return{
      id:0,
    }
},
  mounted(){
    this.id = this.$route.params.id || 0;
  }
}
</script>

<style scoped>

</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

http://localhost:3000/user
在这里插入图片描述
http://localhost:3000/user?123
在这里插入图片描述

路由参数校验

Nuxt.js 可以让你在动态路由组件中定义参数校验方法,如果校验方法返回的值不为 true或Promise中 resolve 解析为false或抛出 Error , Nuxt.js 将自动加载显示 404 错误页面或 500 错误页面。

在pages/users/_id.vue中添加校验方法:

export default {
  validate({ params }) {
    // 必须是number类型
    return /^\d+$/.test(params.id)
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

当携带数字参数时:
在这里插入图片描述
当携带非数字参数时:

嵌套路由

可以通过 vue-router 的子路由创建 Nuxt.js 应用的嵌套路由。

创建内嵌子路由,你需要添加一个 Vue 文件,同时添加一个与该文件同名的目录用来存放子视图组件。

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

假设文件结构如:

pages/
--| users/
-----| _id.vue
-----| index.vue
--| users.vue
  • 1
  • 2
  • 3
  • 4
  • 5

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'
        }
      ]
    }
  ]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

创建user.vue文件与user目录保持平级

<template>
  <div>
    user.vue
    <nuxt-link :to="'/user/123'">携带参数123,去_id.vue页面</nuxt-link>
    <nuxt-child/>
  </div>
</template>

<script>
export default {
  name: "user"
}
</script>

<style scoped>

</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

在user目录下创建_id.vue

<template>
  <div>
    参数id值:{{id}}
  </div>
</template>

<script>
export default {
  name: "_id",
  data(){
    return{
      id:0,
    }
},
  mounted(){
    this.id = this.$route.params.id;
  }
}
</script>

<style scoped>

</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

在这里插入图片描述

http://localhost:3000/user
在这里插入图片描述
在这里插入图片描述

视图

默认布局

Nuxt.js将/layout/default.vue作为所有页面的默认布局,Nuxt.js 允许你扩展默认的布局,或在 layout 目录下创建自定义的布局。

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

<template>
  <div>
    <Nuxt />
  </div>
</template>
  • 1
  • 2
  • 3
  • 4
  • 5

自定义布局

layouts 目录中的每个文件 (顶级) 都将创建一个可通过页面组件中的 layout 属性访问的自定义布局。

创建一个博客布局并将其保存到layouts/blog.vue

<template>
  <div>
    <div>我的博客导航栏在这里</div>
    <nuxt />
  </div>
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

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

<template>
  <div>
    user.vue
    <nuxt-child/>
  </div>
</template>

<script>
export default {
  layout: "blog"
}
</script>

<style scoped>

</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

在这里插入图片描述

异步数据

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

asyncData方法

asyncData方法会在组件(限于页面组件)每次加载之前被调用。它可以在服务端或路由更新之前被调用。在这个方法被调用的时候,第一个参数被设定为当前页面的上下文对象,你可以利用
asyncData方法来获取数据,Nuxt.js 会将 asyncData 返回的数据融合组件 data 方法返回的数据一并返回给当前组件。

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

返回对象

asyncData方法返回data模型数据,在服务端被渲染,最后响应给前端,刷新页面查看页面源代码可以看到name模型数据已在页面源代码中显示。

export default {
   asyncData(){
    return {
      name:'nuxt'
    }
  },
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

返回Promise

使用Promise是异步调用。

export default {
  asyncData({ params }) {
    return axios.get(`https://my-api/posts/${params.id}`).then(res => {
      return { title: res.data.title }
    })
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

使用async或await

nuxt.js中使用async 和 await配合promise可以实现同步调用效果。

export default {
	async asyncData({ store, route }) {
	
    var a = await new Promise(function (resolve, reject) {
      setTimeout(function () {
        console.log("1")
        resolve(1)
      },2000)
    });
    
    var a = await new Promise(function (resolve, reject) {
      setTimeout(function () {
        console.log("2")
        resolve(2)
      },1000)
    });
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

Axios拦截

创建拦截插件

在根目录plugins中新建文件axios.js

import { Message } from 'element-ui'

export default function({$axios, redirect}){
  $axios.onError(err => {
    const {statusCode, message} = err.response.data;
    if(statusCode === 400){
      Message.warning({message});
    }
  })
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

调用插件

修改nuxt.config.js,调用插件

plugins: [
    '@/plugins/element-ui',
    '@/plugins/axios'
],
  • 1
  • 2
  • 3
  • 4

使用vuex/store管理数据

创建状态管理文件

store文件夹新建user.js

/**
 * 用户状态管理
 * @returns {{userInfo: {user: {}, token: string}}}
 */
export const state = () => ({
  userInfo: {
    token: '',
    user: {},
  },
})

export const mutations = {
  /**
   * 保存用户信息到state
   * @param state
   * @param data
   */
  setUserInfo (state, data) {
    console.log('mutations---setUserInfo')
    state.userInfo = data
  },
  
	
}

export const actions = {
  /**
   * 登录
   * @param commit
   * @param data
   * @returns {Promise<AxiosResponse<any>>}
   */
  login ({ commit }, data) {
    console.log('actions---login')
    return this.$axios({
      url: '/user/login',
      method: 'POST',
      data: data
    }).then(res => {
      const data = res.data
      commit('setUserInfo', data)
      return data
    })
  }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

使用状态管理

methods: {
    clickChange () {
      // this.$store.commit('user/setUserInfo',"ok")
      this.$store.dispatch('user/login', this.form).then(res => {
        // 跳转到首页
        setTimeout(() => {
          this.$router.replace('/')
        }, 1000)
      })
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

显示用户信息

  <div v-if="$store.state.user.userInfo.token">
        <h3>{{$store.state.user.userInfo.user.name}}</h3>
 </div>
  • 1
  • 2
  • 3

保存store到本地

现在可以将数据保存到store了,但是数据是保存在缓存中的,如果页面一刷新,那么数据就会丢失。所以需要使用localStorage把数据保存到本地,但是由于nuxtjs是运行在服务器的,不能直接在store中使用浏览器的方法,所以需要借助插件vuex-persistedstate,把本地存储的数据读取到store

插件地址:https://github.com/robinvdvleuten/vuex-persistedstate

安装插件

npm install --save vuex-persistedstate
  • 1

在根目录plugins中新建文件localStorage.js

import createPersistedState from 'vuex-persistedstate'

export default ({store}) => {
    window.onNuxtReady(() => {
        createPersistedState({
        	// 读取本地存储的数据到store
            key: "store",
        })(store)
    })
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

修改nuxt.config.js配置文件,在plugins配置项中新增一条数据

plugins: [
    { src: '@/plugins/localStorage', ssr: false }
],
  • 1
  • 2
  • 3

数据清除

export const mutations = {
  /**
   * 清除用户数据
   * @param state
   * @param info
   */
  cleanUserInfo (state, info) {
    if (process.browser) {
      localStorage.removeItem('userInfo')
    }
    state.userInfo = {}
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
 this.$store.commit('user/cleanUserInfo')
  • 1
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/971351
推荐阅读
相关标签
  

闽ICP备14008679号