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

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

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

服务端渲染:

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. 然后,再去请求 index.html 中通过 script 引入的 JS 文件,浏览器下载完成后,解析执行,生成完整的 HTML 页面后渲染显示。
单页应用主要的两个问题:
  1. 不利于 SEO 搜索引擎优化。

    1. 百度的服务器集群 24 小时不间断地在网络上爬取数据,爬取单页应用的时候其实主要就是把网站的 index.html 下载下来,但是单页应用的 index.html 中的 body 内其实只有一个 div 而已(使用 Webpack 打包构建),虽然 meta 等配置信息也是可以被爬取到的,但是页面的具体内容是爬取不到的。因此在百度的数据库中收录的网站的关键字很少,当用户在浏览器中通过百度的搜索引擎来搜索关键字的时候,由于匹配到的关键字很少,匹配度很低,因此排名会很靠后。
    2. 对比早期的 SSR 的页面,服务器会直接生成完整的 HTML 页面后再返回给客户端,爬虫从网页中就能爬取到更多有效的数据。

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

  2. 首屏渲染速度慢:

    1. 单页应用首次请求到的只是一个 index.html 页面,然后才会去请求 index.html 中通过 script 引入的 JS 文件,浏览器下载完成后,还需要解析执行,生成完整的 HTML 页面后才会渲染显示。
    2. 对比早期的 SSR 的页面,服务器会直接生成完整的 HTML 页面后再返回给客户端,客户端下载到的直接就是完整的网站,直接渲染出来显示就可以了。

    不过,现代浏览器执行 JS 的速度已经很快了,差异也不是特别巨大。

后端路由和前端路由:

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

后端路由:

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

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

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

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

前端路由:

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

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

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

hash 模式:

hash 模式利用的是浏览器不会对 # 号后面的路径对服务端发起路由请求。

可以通过 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'
      return
    case '#/about':
      routerView.innerHTML = 'About'
      return
    default:
      return
  }
}
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'
      return
    case '/about':
      routerView.innerHTML = 'About'
      return
    default:
      return
  }
}

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值