服务端渲染和客户端渲染、多页应用和单页应用、后端路由和前端路由

任何一个技术的出现都不是凭空产生的,一定是为了解决原有技术上的痛点。

服务端渲染和客户端渲染:

服务端渲染:

SSR:Server Side Rendering,服务端渲染。指的是服务器端生成完整的 HTML 页面后,发送给客户端直接渲染呈现。早期的页面都是通过服务器端渲染来完成的。

服务端渲染的缺点:有可能某次请求只是一些数据发生了变化,但服务器却需要重绘整个 HTML 页面,返回给浏览器重新渲染,不仅浪费了带宽,也增加了浏览器的性能消耗。

请添加图片描述

客户端渲染:

CSR:Client Side Rendering,客户端渲染。指的是客户端先解析服务器端发送过来的文件生成完整的 HTML 页面,再渲染呈现。这种模式就是前后端分离。

SPA 页面通常依赖的就是客户端渲染。

请添加图片描述

多页应用和单页应用:

多页应用:

一个 Web 应用包含很多 HTML 页面。每一次页面跳转的时候,服务器都会给返回一个新的 HTML 文档。

单页应用(single page application、SPA、单页面富应用):

整个应用只有一个完整的页面,点击页面中的链接不会刷新页面,只会做页面的局部更新。第一次进入页面的时候会请求一个 HTML 文件,跳转到其他路径,并不会请求新的 HTML 文件,但是页面内容也变化了。

单页应用的原理:

JS 会感知到 URL 的变化,通过这一点,可以利用 JS 动态的将当前的内容清除掉,然后将新的内容挂载到当前页面上。

单页应用的渲染流程:
  1. 首先浏览器根据域名或者 IP 地址向服务器请求一个 index.html 文件。
  2. 然后对其解析执行,生成完整的 HTML 页面后渲染显示;在这个过程中,如果发现 HTML 中有引入其他的文件,对其进行请求、解析、执行。
单页应用的缺点:
  1. 不利于 SEO (Search Engine Optimization)搜索引擎优化:例如百度的服务器集群 24 小时不间断地在网络上爬取数据,爬取单页应用的时候其实主要就是把网站的 index.html 下载下来,但是单页应用的 index.html 中的 body 内其实只有一个 div 而已(使用 Webpack 打包构建),虽然 meta 等配置信息也是可以被爬取到的,但是页面的具体内容是爬取不到的。因此在百度的数据库中收录的网站的关键字很少,当用户在浏览器中通过百度的搜索引擎来搜索关键字的时候,由于匹配到的关键字很少,匹配度很低,因此排名会很靠后。

    谷歌在爬取数据方面做得要比百度好,也会执行 JS 文件,爬取单页应用时爬取到的关键字也会更多一些。

  2. 首屏渲染速度慢:页应用首次请求到的只是一个 index.html 页面,在解析的过程中发现有引入其他类型的文件,才会去请求下载,最后才会解析执行生成完整的 HTML 页面后渲染显示。

单页应用的 SEO 搜索引擎优化:

多页应用时,可以通过配置每个 HTML页面的 title 标题、meta 标签的 keywords 关键字、meta 标签的 descriptors 描述来进行 SEO。

  1. 预渲染:在构建时就简单地生成针对特定路由的静态 HTML 文件。以 Vue 为例,可以使用 prerender-spa-plugin 插件预渲染页面,搭配 vue-meta-info 插件配置标题、关键字、描述。

    缺点:不适合有大量的页面需要 SEO 的情况,需要一个页面一个页面手动去配置;动态改变标题、关键字、描述是无效的。

    // vue.config.js
    const path = require('path')
    const PrerenderSPAPlugin = require('prerender-spa-plugin');
     
    module.exports = {
    	configureWebpack: {
    	    plugins: [
    	      new PrerenderSPAPlugin({
    	        staticDir: path.join(__dirname, 'dist'),
    	        routes: [
    	          '/',
    	          '/home',
    	          '/member',
    	        ],
    	      }),
    	    ],
      },
    }
    
    // main.js
    import Vue from 'vue'
    import MetaInfo from 'vue-meta-info'
    Vue.use(MetaInfo)
    
    // 在 vue 页面中使用
    export defaultes {
    	metaInfo() {
    	    return {
    	      title: '标题',
    	      meta: [{
    	        name: '关键字',
    	        content: '描述'
    	      }]
    	 }
      },
    }
    
  2. 服务端渲染:服务器端生成完整的 HTML 页面后,发送给客户端直接渲染呈现。以 Vue 为例,可以使用开箱即用的 Nuxt.js
    缺点:一套代码两套执行环境,会引起各种问题,例如 服务端没有window、document 等对象。

后端路由和前端路由:

路由:一个路由就是一个映射关系(key-value:key 就是路径,value 就是 Function 或者 Component)。

后端路由:

早期的网站开发,整个 HTML 页面都是由服务器来生成的。每个页面都有自己对应的 URL,客户端发送 URL 给服务器,服务器通过对该 URL 进行匹配后生成对应的 HTML 页面,返回给客户端进行展示。

客户端请求不同的 URL,服务器生成好对应的整个页面后将页面返回给客户端,这就是后端路由。本质上就是 URL 请求地址与服务器资源之间的对应关系。在后端路由中一个路径对应一个 Function,用来处理客户端提交的请求。

后端路由会刷新整个页面。

以下为 Node 的后端路由:当 Node 接收到一个请求时,根据请求路径找到匹配的路由,调用路由中的函数来处理请求,返回响应函数。
请添加图片描述

前端路由:

前端路由的核心是 URL 发生变化,但是并不会向服务器发送新的请求,页面不会进行整体的刷新。本质上就是检测 URL 的变化,然后解析来匹配路由规则,渲染对应的组件,通过 JavaScript 来实现页面内容的更换。在前端路由中一个路径对应一个 Component,用于展示页面内容。

前端路由不会刷新整个页面。

主流的实现方式是通过 hash 模式和 history 模式。

hash 模式:

hash 模式利用的是 URL # 号后面的内容发生变化,浏览器不会向服务端发起新的请求。

可以通过 hashchange 事件监听 URL 的变化。

hash 是 URL 中 # 及后面的部分,常用作锚点在页面内进行导航。

<body>
  <ul>
    <!-- 定义路由 -->
    <li><a href="#/home">home</a></li>
    <li><a href="#/about">about</a></li>

    <!-- 渲染路由对应的 UI -->
    <div id="routeView"></div>
  </ul>
</body>

// 页面加载完不会触发 hashchange,这里主动触发一次 hashchange 事件
window.addEventListener('DOMContentLoaded', onLoad)
// 监听路由变化
window.addEventListener('hashchange', onHashChange)

// 路由视图
var routerView = null

function onLoad () {
  routerView = document.querySelector('#routeView')
  onHashChange()
}

// 路由变化时,根据路由渲染对应 UI
function onHashChange () {
  switch (location.hash) {
    case '#/home':
      routerView.innerHTML = 'Home'
      break
    case '#/about':
      routerView.innerHTML = 'About'
      break
    default:
      break
  }
}
history 模式:

history 模式利用的是 HTML5 中新增的 history API。history API 用来操作浏览器的路由地址。浏览器会提供一个 history 对象,用来保存用户操作过的历史 URL,使用前进后退按钮时,URL 地址会发生变化,但不会向服务器发送请求,不会触发页面的整体刷新。因此可以使用 pushState 和 replaceState 这两个 API 将 URL 添加到 history 历史记录中就可以实现不发送请求的路由跳转。

可以通过 popstate 事件来监听 URL 的变化,通过 pushState 和 replaceState 这两个方法改变 URL 的 path 部分而不引起页面的整体刷新。

<body>
  <ul>
    <!-- 定义路由 -->
    <li><a href="#/home">home</a></li>
    <li><a href="#/about">about</a></li>

    <!-- 渲染路由对应的 UI -->
    <div id="routeView"></div>
  </ul>
</body>

// 页面加载完不会触发 popstate,这里主动触发一次 popstate 事件
window.addEventListener('DOMContentLoaded', onLoad)
// 监听路由变化
window.addEventListener('popstate', onPopState)

// 路由视图
var routerView = null

function onLoad () {
  routerView = document.querySelector('#routeView')
  onPopState()

  // 拦截 <a> 标签点击事件默认行为, 点击时使用 pushState 修改 URL并更新手动 UI,从而实现点击链接更新 URL 和 UI 的效果。
  var linkList = document.querySelectorAll('a[href]')
  linkList.forEach(el => el.addEventListener('click', function (e) {
    e.preventDefault()
    history.pushState(null, '', el.getAttribute('href'))
    onPopState()
  }))
}

// 路由变化时,根据路由渲染对应 UI
function onPopState () {
  switch (location.pathname) {
    case '/home':
      routerView.innerHTML = 'Home'
      break
    case '/about':
      routerView.innerHTML = 'About'
      break
    default:
      break
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值