theme: channing-cyan
服务端总结&单页面开发概念
一.服务端语言
服务端语言是什么?它是运行在服务器上,可用于读写数据库、编写服务逻辑的语言。
我并不想把这件事情描述的太复杂,因为归根结底它就是做这两件事。
至于服务端语言的选择,完全是根据业务和自身能力相结合。比如我是一个前端开发,我更倾向于选择 Node
作为服务端开发语言,因为 js 可以去写后端。
这里强调一下,
Node
它本身不是一门语言,而是一个开发环境,基于谷歌的 V8 引擎,能让JavaScript
可以运行在服务器的一个环境。赋予JavaScript
更多除了浏览器脚本意外的能力,如IO
操作等。
二.数据库
数据库的作用,是用于数据的持久化存储。
本项目选择 MySQL
作为数据库,是因为它作为老牌数据库,网上解决方案比较多,若是在开发过程中遇到问题,可以在搜索引擎上轻松找到自己遇到的问题的解决方案,对于新手而言,项目开发的流畅度是关键,完成一整套项目的开发之后,当然可以尝试去选择其他更有意思的数据库,这里不展开描述。
本教程采用 egg-mysql
插件进行数据库的操作。官方推荐使用 Sequelize
来应对较为复杂的项目。初衷是希望大家能快速入门,不希望引入过多的复杂概念,这里如果在后续的学习过程中有需要应对更为复杂的项目时,可以考虑引入 Sequelize
。
三.项目分析
整个项目是基于 Egg.js
作为上层架构,通过 Egg.js
提供的一些预定好的开发形式,轻松地完成了下列十余个接口的开发:
项目不大,但是本项目包含了几个关键的知识点:
- 多用户鉴权
- 一套增删改查
- 表数据的二次处理(图表)
- 列表分页的制作
- 文件数据上传
用“麻雀虽小、五脏俱全”来形容,哈哈哈。
如果想要在此基础上拓展一些新的功能,如朋友圈、笔记、博客等,都是可以基于该项目进行二次开发的,因为多用户鉴权的架子已经搭建好,后续要做的就是添加表,以及一些业务逻辑上的处理。
当然,如果想做更为复杂的项目,比如一个商城。那涉及到的内容可能就更多了,单论商品模块的后台编辑,前台展示,就涉及到 sku
、购物车、库存的处理、多图上传、详情编辑、类型筛选等等。这就很考验知识储备和解决问题的能力了。
四.前端框架单页面概念
服务端的内容基本上已经结束,从这开始,带进入前端部分的实战环节。本项目前端部分使用 React
作为前端框架,所以先理解什么是单页面,它是怎样实现页面组件之间的切换,路由的原理等知识点。
- 传统页面 DOM 直出
- 单页面原理
- 前端路由实现
1.单页面
前端自从进入三大框架时代以来,传统的多页面开发已渐渐淡出人们的视线。为了更好的了解现在,先要去知道它的过去。
2.传统页面
这里不纠结叫法,凡是整个项目都是 DOM
直出的页面,都称它为“传统页面”(SSR 属于首屏直出,这里我不认为是传统页面的范畴)。那么什么是 DOM
直出呢?简单说就是在浏览器输入网址后发起请求,返回来的 HTML
页面是最终呈现的效果,那就是 DOM
直出。并且每次点击页面跳转,都会重新请求 HTML
资源。耳听为虚,眼见为实。以这个地址为例,验证以下上述说法。
https://www.cnblogs.com/han-1034683568/p/14126727.html#4773138
腚眼一看,就能明白上图在描述什么。没错,博客园就是一个传统页面搭建而成的网站,每次加载页面,都会返回 HTML
资源以及里面的 CSS
等静态资源,组合成一个新的页面。打开后如下所示:
网页上能看到什么图片或文字,你能在上述图片中找到相应的 HTML
结构,那也属于传统页面,也就是 DOM
直出。
3.单页面
时代在进步,科技在发展,面对日益增长的网页需求,网页开始走向模块化、组件化的道路。随之而来的是代码的难以维护、不可控、迭代艰难等现象。面临这种情况,催生出不少优秀的现代前端框架,首当其冲的便是 React
、 Vue
、 Angular
等著名单页面应用框架。而这些框架有一个共同的特点,便是“通过 JS
渲染页面”。 举个例子,以前直出 DOM
,而现在运用这些单页面框架之后, HTML
页面基本上只有一个 DOM
入口,大致如下所示:
所有的页面组件,都是通过运行上图底部的 app.js
脚本,挂载到 <div id="root"></div>
这个节点下面。用一个极其简单的 JS
展示挂载这一个步骤: ```js
```
所有的节点都通过 createElement
方法创建,最终通过 appendChild
的形式插入到 root
根节点。
那么问题来了,如果有十几个页面需要这样的操作咋整?
这时候「前端路由」应运而生,它的出现就是为了解决单页面网站多个页面组件切换。通过切换浏览器地址路径,来匹配相对应的页面组件。通过一张丑陋的图片来理解这个过程:
「前端路由」会根据浏览器地址栏 pathname
的变化,去匹配相应的页面组件。然后将其通过创建 DOM
节点的形式,塞入根节点
。这就达到了无刷新页面切换的效果,从侧面也能说明正因为无刷新,所以 React
、 Vue
、 Angular
等现代框架在创建页面组件的时候,每个组件都有自己的「生命周期」。
4.路由实现原理
「前端路由」插件比较火的俩框架对应的就是 Vue-Router
和 React-Router
,但是它们的逻辑,归根结底还是一样的,用殊途同归四个字,再合适不过。
通过分析「哈希模式」和「历史模式」的实现原理,对前端路由的原理有一个更深刻的理解。
哈希模式(hash)
a
标签锚点大家应该不陌生,而浏览器地址上 #
后面的变化,是可以被监听的,浏览器提供了原生监听事件 hashchange
,它可以监听到如下的变化:
- 点击
a
标签,改变了浏览器地址。 - 浏览器的前进后退行为。
- 通过
window.location
方法,改变浏览器地址。
接下来利用这些特点,去实现一个 hash 模式的简易路由: 在线运行
```html
```
当然,这是很简单的实现,真正的 hash 模式,还要考虑到很多复杂的情况,大家有兴趣就去看看源码。
历史模式(history)
history
模式会比 hash
模式稍麻烦一些,因为 history
模式依赖的是原生事件 popstate
,下面是来自 MDN 的解释:
小知识:pushState 和 replaceState 都是 HTML5 的新 API,他们的作用很强大,可以做到改变浏览器地址却不刷新页面。这是实现改变地址栏却不刷新页面的重要方法。
包括 a
标签的点击事件也是不会被 popstate
监听。需要想个办法解决这个问题,才能实现 history
模式。
解决思路:可以通过遍历页面上的所有 a
标签,阻止 a
标签的默认事件的同时,加上点击事件的回调函数,在回调函数内获取 a
标签的 href
属性值,再通过 pushState
去改变浏览器的 location.pathname
属性值。然后手动执行 popstate
事件的回调函数,去匹配相应的路由。逻辑上可能有些饶,用代码来解释一下:在线地址
```html
```
这里注意,不能在浏览器直接打开静态文件,需要通过 web 服务,启动端口去浏览网址。默认打开的协议是 file 协议,它是不会被
popstate
监听的。
五.总结
上述内容,基本上对前端单页面的实现原理有了一个大概的雏形,更深入的学习还是需要再对框架的源码进行分析。