SPA 单页面应用
优点:
- 用户体验好
- 开发效率高
- 渲染性能好
- 可维护性好
缺点:
- 首屏渲染时间长
- 不利于SEO
借鉴了传统的服务端渲染:
-
客户端请求一个地址
- 服务端查询页面所需要的数据,数据库返回数据
- 服务端将数据结合页面模板渲染为HTML,返回HTML给客户端
客户端激活为SPA应用
同构应用
- 通过服务端渲染首屏直出,解决SPA应用首屏渲染慢以及不利于SEO的问题
- 通过客户端渲染接管页面内容交互得到更好的用户体验
渲染
把 【数据】 + 【模板】 拼接到一起
传统的服务端渲染 (SSR)
演示使用的 express
npm i express
// 安装 art-template 用于渲染
const html = artTemplate.render(tpl, data)
// 模板文件中遍历数据
<ul>
{{ each posts }} // 遍历 posts
<li>{{ $value.title }}</li>
{{ /each }}
</ul>
完整版代码:
// index.js
const express = require('express')
const fs = require('fs')
const artTpl = require('art-template')
const app = express()
app.get('/', (req, res) => {
// 1. 获取页面模板
const tplStr = fs.readFileSync('./index.html', 'utf-8')
// 2. 获取数据
const data = JSON.parse(fs.readFileSync('./index.json', 'utf-8'))
// 3. 渲染: 数据 + 模板 = 最终结果
const html = artTpl.render(tplStr, data)
res.send(html)
})
app.listen('3000', () => {
console.log('监听中')
})
// index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>服务端渲染</title>
</head>
<body>
<h1>{{ title }}</h1>
<ul>
{{ each posts }}
<li>{{ $value.name }}</li>
{{ each }}
</ul>
</body>
</html>
缺点:
- 前后端代码完全耦合在一起,不利于开发和维护
- 前端没有足够的发挥空间
- 服务端压力大
- 用户体验一般
客户端渲染 (CSR: Client Side Render)
Ajax 使得客户端动态获取数据成为可能。
首屏渲染慢
服务端渲染的页面,客户端只需要发送一次请求即可。
客户端渲染则需要三次进去: html页面请求,js 文件的请求,动态数据的请求。
不利于 SEO
客户端渲染第一次发送请求,返回的页面是空的。
现代化的服务端渲染
基于 React、Vue等框架,客户端渲染和服务器端渲染的结合
- 在服务器端执行一次,用于实现服务器端渲染(首屏直出)
- 在客户端再执行一次,用于接管页面交互
大体过程:
- 客户端请求一个地址
- 服务端查询页面所需的数据,数据库返回数据
- 服务端渲染页面及生成客户端SPA脚本,返回HTML(渲染好的页面内容 + 客户端 SPA脚本)
- 客户端呈现服务端返回的HTML, 通过页面中的脚本激活为SPA应用,之后的页面交互都是客户端渲染。
如何实现同构渲染:
- 使用Vue、React等框架的官方解决方案(搭建麻烦)
- 使用第三方解决方案:
- Vue生态的Nuxt.js
- React生态的Next.js
Nuxt通过渲染
// 基本使用
npm init -y
npm install nuxt
// 运行
npx nuxt / npm run dev
// index.vue
export default{
name: 'Home',
components: {},
// asyncData() 是 Nuxt 中特殊提供的一个钩子函数,专门用于获取页面服务端渲染的数据
async asyncData(){
const { data } = await axios({
method: 'GET',
url: 'https://localhost:3000/data.json'
})
// 这里返回的数据,会和data(){} 中的数据合并到一起给页面使用
return data
}
}
// layouts/default.vue 是所有页面的父模板,用于客户端渲染
<template>
<div>
<!-- 路由出口 -->
<ul>
<li>
<!-- 类似于router-link, 单页面应用导航-->
<nuxt-link to="/">Home</nuxt-link>
</li>
</ul>
<nuxt />
</div>
</template>
<script>
export default{
}
</script>
同构渲染的问题
开发条件有限:
- 浏览器特定的代码只能在某些生命周期钩子函数中使用
- 一些外部扩展库可能需要特殊处理才能在服务端渲染应用中运行
- 不能在服务端渲染期间操作DOM
- 某些代码操作需要区分运行环境
客户端渲染:
- 仅构建客户端应用即可
- 可以部署在任意Web服务器中
同构渲染:
- 需要构建两个端
- 只能部署在Node.js Server
更多的服务器负载