SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)

一.前言

开始之前,我们先了解一下普通前端渲染过程:

SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第1张图片

而加了SSR的服务器渲染过程:

SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第2张图片
明显请求次数变少了,速度更快.那接下来隆重介绍服务端渲染

什么是服务器端渲染

  • 前端渲染:html页面作为静态文件存在,前端请求时后端不对该文件做任何内容上的修改,直接以资源的方式返回给前端,前端拿到页面后,根据写在html页面上的js代码,对该html的内容进行修改。
  • 服务端渲染:前端发出请求后,后端在将HTML页面返回给前端之前,先把HTML页面中的特定区域,用数据填充好,再将完整的HTML返回给前端。在SPA场景下,服务端渲染都是针对第一次get请求,它会完整的html给浏览器,浏览器直接渲染出首屏,用不着浏览器端多一个AJAX请求去获取数据再渲染。

为什么使用服务器端渲染

优点:

  • 更好的 SEO.
    因为传统的搜索引擎只会从 HTML 中抓取数据,这会导致前端渲染的页面无法被抓取。
  • 更快的内容到达时间.
    特别是对于缓慢的网络情况或运行缓慢的设备,页面首屏时间大概有80%消耗在网络上,剩下的时间在后端读取数据以及浏览器渲染,显然要优化后面的20%是比较困难的,优化网络时间是效果最明显的手段。传统的Ajax请求是先请求js再由js发起数据请求,两项时间再加上浏览器渲染时间才是首屏时间。而SSR能将两个请求合并为一个。

缺点:

  • 更多的服务器端负载。
  • 服务器端和浏览器环境差异带来的问题,例如document等对象找不到的问题。

如何选择

建议:如果注重SEO的新闻站点,非强交互的页面,建议用SSR;像后台管理页面这类强交互的应用,建议使用前端渲染。

二.Nuxt.js学习

Nuxt.js是什么?

引用官网官网的一句话:Nuxt.js是一个基于Vue.js的通用应用框架.

开始第一个hello world应用

安装

//安装包-全局安装(已装的省略这步)
yarn add create-nuxt-app -globel
//创建项目
npm init nuxt-app 项目名
//运行项目
npm run dev

创建项目时选择的内容
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第3张图片
目录分析

└─my-nuxt-demo
  ├─.nuxt               // Nuxt自动生成,临时的用于编辑的文件,build
  ├─assets              // 用于组织未编译的静态资源如LESS、SASS或JavaScript,对于不需要通过 Webpack 处理的静态资源文件,可以放置在 static 目录中
  ├─components          // 用于自己编写的Vue组件,比如日历组件、分页组件
  ├─layouts             // 布局目录,用于组织应用的布局组件,不可更改⭐
  ├─middleware          // 用于存放中间件
  ├─node_modules
  ├─pages               // 用于组织应用的路由及视图,Nuxt.js根据该目录结构自动生成对应的路由配置,文件名不可更改⭐
  ├─plugins             // 用于组织那些需要在 根vue.js应用 实例化之前需要运行的 Javascript 插件。
  ├─static              // 用于存放应用的静态文件,此类文件不会被 Nuxt.js 调用 Webpack 进行构建编译处理。 服务器启动的时候,该目录下的文件会映射至应用的根路径 / 下。文件夹名不可更改。⭐
  └─store               // 用于组织应用的Vuex 状态管理。文件夹名不可更改。⭐
  ├─.editorconfig       // 开发工具格式配置
  ├─.eslintrc.js        // ESLint的配置文件,用于检查代码格式
  ├─.gitignore          // 配置git忽略文件
  ├─nuxt.config.js      // 用于组织Nuxt.js 应用的个性化配置,以便覆盖默认配置。文件名不可更改。⭐
  ├─package-lock.json   // npm自动生成,用于帮助package的统一设置的,yarn也有相同的操作
  ├─package.json        // npm 包管理配置文件
  ├─README.md

重点关注下面几个文件夹
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第4张图片
修改pages/index.vue文件,增加hello world ,效果如下:
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第5张图片

路由学习
pages文件夹里的默认路由

在pages文件夹里写一个测试页面,发现在浏览器地址里加文件名成功访问到了这个页面
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第6张图片
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第7张图片
同样加上文件夹也可以匹配,推荐文件夹这种写法,写文件名不是不可以,文件名容易出错.
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第8张图片
如果文件名起名为index.vue,它默认会打开这个index.vue页面.

pages文件夹路由总结:
Nuxt.js会根据pages目录结构会自动生成对应的路由配置.

内部路由实现的原理(其实就是原始的vue路由):
假设pages文件夹目录如下:

└─pages
    ├─index.vue
    └─user
      ├─index.vue
      ├─one.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'
    }
  ]
}
路由跳转(跟vue一样,也有两种)

标签跳转:

<nuxt-link to="/student"></nuxt-link>

api跳转:

this.$router.push('/student')

SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第9张图片
这两种方式实现效果一样.

动态路由(实际动态传参)

跳转前携带参数:
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第10张图片
准备好组件
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第11张图片
跳转效果:
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第12张图片SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第13张图片
获取传递的参数:

$route.params.id

SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第14张图片
说明:

$route.params.id这里的id对应一个加了下划线的文件夹名,也就是假设你把id换成了qita,那你的文件夹也要起名为_qita即可.
路由传递参数校验

上面的路由参数传递方式是没有做类型限制的你把item.id改为item.name也可以传递字符串,那我们怎么做参数类型限制呢?

SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第15张图片
Nuxt.js 可以让你在动态路由对应的页面组件中配置一个validate方法用于校验动态路由参数的有效性。该函数有一个布尔类型的返回值,如果返回true则表示校验通过,如果返回false则表示校验未通过。

嵌套路由

嵌套路由指的是在当前页面中再显示一个新的页面,相当于父页面还在,只是增加了一个子页面
第一步准备好父组件teacher.vue
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第16张图片:
第二步:同时必须创建一个相同类名的teacher文件夹,在这个teacher文件夹下面也要创建以斜杠命名的文件夹_id,在_id文件夹里创建子页面index.vue.
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第17张图片
第三步:回到父页面teacher.vue,用nuxt-child标签写显示出口即可实现.
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第18张图片
实现效果:
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第19张图片

布局组件

比如有这么一个需求:studdent和teacher页面都希望有一个头部导航组件,那在nuxt.js中怎么来实现呢?
第一步:
在layouts文件夹里,创建自己的公共头部导航组件,在这个头部导航里同时准备一个nuxt组件作为坑(其它页面引用的页面都会丢在这个坑里,这个坑很重要)
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第20张图片
引用的Mynav组件内容(组件内容一般放在components文件夹里)
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第21张图片
第二步:在需要导航的组件里添加layout属性,值就是自己在layout文件夹里定义的文件名即可
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第22张图片
实现效果:
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第23张图片

404组件(nuxt里叫error.vue组件,nuxt里名字也只能叫这个error.vue)

其实特别简单,你只需要在layout文件夹里新建一个error.vue页面即可
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第24张图片
输入错误的网站就自动会出来
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第25张图片

全局样式的应用

在assets文件里创建样式文件(这个跟我们平时一样)
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第26张图片
引入进行使用(这一步比较特殊):
找到nuxt.config.js文件,在css属性数组里填入自己的路径地址即可
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第27张图片
这样全局样式就生效啦.

使用element-UI

其实很简单,三步走
第一步:安装

npm install element-ui -S

第二步:在plugins文件夹下面,创建ElementUI.js文件(创建地方比较特殊)

import Vue from 'vue'
import ElementUI from 'element-ui'
Vue.use(ElementUI)

第三步:在nuxt.config.js中添加配置

css: [
  'element-ui/lib/theme-chalk/index.css'
],
plugins: [
//ssr:true表示这个插件只在服务器端起作用
  {src: '~/plugins/ElementUI', ssr: true }
],
build: {
//防止elementUI多次打包
  vendor: ['element-ui']
}

修改配置后重启就可以使用.

异步获取数据

注意:在nuxt.js中只有created和beforeCreated这两个生命周期函数才能在服务器端进行正常使用.
下面模拟异步获取数据
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第28张图片
秒后正常加载出来数据,但这样是有问题的,因为前端也会执行一次,我们不希望前端执行,所以很重要一点在nuxt中发异步请求不能写在created生命周期里,正确做法是写在asyncData方法里.
正确做法:
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第29张图片
同理模拟一个promise异步,也能获取异步数据
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第30张图片
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第31张图片

总结:Nuxt.js 扩展了 Vue.js,增加了一个叫 asyncData 的方法,使得我们可以在设置组件的数据之前能异步获取或处理数据。asyncData方法会在组件(限于页面组件)每次加载之前被调用。它可以在服务端或路由更新之前被调用。所以需要注意这个函数中不能使用this
注意:常规写法如果在created钩子中写异步,是在客户端渲染的而不是在服务端.而我们的是服务器端.

使用方法:
asyncData(context, callback) {callback(null, data)}
其中,
context.route.params.xxx可以获取参数

axios请求数据
在请求之前,隆重介绍一个本地服务数据工具json-server的使用
1. 下载json-server工具:npm i json-server -g

2. 开启服务: json-server --watch db.json --port 3301

然后准备好数据之后,在浏览器里输入对应的属性名即可访问到对应数据,非常方便
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第32张图片
使用axios步骤:
1.安装npm install --save axios
2.使用:

import axios from 'axios'

asyncData(context, callback) {
  axios.get('http://localhost:3301/in_theaters')
    .then(res => {
      console.log(res);
      callback(null, {list: res.data})
    })
}

SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第33张图片
3.为防止重复打包,在nuxt.config.js中配置

module.exports = {
  build: {
    vendor: ['axios']
  }
}

多个这样配置
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第34张图片
优化axios:设置基地址和超时时间
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第35张图片
优化后效果也是一样的.

三.豆瓣电影项目

首页

新建目录
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第36张图片
准备layout
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第37张图片
使用layout
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第38张图片
写MovieHeader公共组件
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第39张图片
在layout/movie.vue使用上面的组件
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第40张图片
优化样式后效果:(采用的是固定定位+flex布局)
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第41张图片

电影页

新建movie/_type/index.vue文件,里面写如下代码

<template>
    <div class="movie-type">
        <!-- $route.params.type:是vue的方式获取路由参数 -->
        <nuxt-link class="movie-box" :to="`/movie/${$route.params.type}/${item.id}`" v-for="item in movieList" :key="item.id">
            <img :src="item.img" :alt="item.title">
            <h4>电影名:{{item.title}}</h4>
            <p>上映评分:{{item.rating===0?'暂无评分':item.rating}}</p>
        </nuxt-link>
    </div>
</template>
<script>
import axios from '~/plugins/axios'
export default {
  data() {
    return {
      movieList: []
    }
  },
  layout: 'movie',
  asyncData(context, callback) {
    //获取动态路由参数
    let type = context.route.params.type
    // console.log(type);//得到路由参数

    axios.get(`/${type}`).then(res => {
      // console.log(res);
      callback(null, {
        movieList: res.data
      })
    })
  }
}
</script>
<style  scoped>
.movie-type {
    display: flex;
    flex-direction: column;
    align-items: center;
}
.movie-box{
    display: flex;
    flex-direction: column;
    align-items: center;
    margin: 20px 0;
    padding: 10px 0;
    width:20%;
    box-shadow: 0 0 10px #bbb;
    color: #000;
}
.movie-box:hover{
    box-shadow: rgba(0,0,0,.3) 0 19px 60px;
}
</style>

效果:
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第42张图片

电影详情页

新建movie/_type/_id/index.vue文件,里面写如下代码

<template>
    <div class="movie-detail">
       <div class="detail-wrapper">
           <img
         :src="movieDetail.img"
         :alt="movieDetail.title"
        >
        <h1>{{movieDetail.title}}</h1>
        <p>上映时间: {{movieDetail.details[0].year}}</p>
        <p>电影类型: {{movieDetail.genres.join(',')}}</p>
        <p>电影简介:{{movieDetail.details[0].summary}}</p>
       </div>
    </div>
</template>
<script>
import axios from '~/plugins/axios'
export default {
    data(){
        return {
            movieDetail:{}
        }
    },
    layout:'movie',
    asyncData(context,callback){
        axios.get(`/${context.route.params.type}/${context.route.params.id}?_embed=details`)
        .then(res=>{
            console.log(res);
            callback(null,{
                movieDetail:res.data
            })
        })
    }
}
</script>
<style scoped>
.movie-detail{
  
    width: 20%;
    margin: 0 auto;
    box-sizing: border-box;
    box-shadow: 0 0 10px #bbb;
}
.detail-wrapper{
    text-align: center;
}
</style>

效果:
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第43张图片

SEO搜索引擎优化

设置全局seo
在nuxt.config.js里的head进行设置即可:
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第44张图片
局部设置单独页面seo的方法:
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第45张图片
效果:
SSR服务器端渲染(Nuxt.js总结和豆瓣电影项目)_第46张图片
最终完整效果:

最后附上源码克隆地址:
github.com:huanggengzhong/SSR.git

你可能感兴趣的:(二十二.SSR,十七.React)