spa来源
传统的web, 浏览器输入一个url然后返回一个页面.后来, 人们发现这样太浪费资源啦, 比如, 我可能只是一个很小的操作,给空间好友点赞啊之类的 这个时候刷新页面肯定是不行的啊, 那就'局部刷新'吧,就是后来的ajax的应用.
再后来, 机智的开发者又想到, hash路径段(形如#header)是不会像服务器发请求的, 那么我们可以在点击一个锚点的时候加载一个小页面, 局部刷新, 再加上可以操作浏览器的历史记录来实现回退等功能. 那干脆就搞个前端路由吧. 于是前端路由就出现啦.
其实前端路由本质上也是一种局部刷新, 但是更规范. 这次刷新, 拉回来的是一个完整的组件, 这个组件包含了视图和数据. 这里的数据又分为两种, 一种是后端传过来的, 暂且成为数据库数据, 另一种是为了更好地管理视图而在前端生成的数据, 暂且成为视图数据.一通乱说过后, 我们就可以好好分析一下SPA到底是个什么东西啦.SPA是single page application的简称, 中文叫单页应用. 何为单页? 就是只有一个页面, 这个页面一般是index.html, 这是项目的入口文件. 自项目启动到结束, 浏览器中始终都是这个页面, 你看到的变化只是组件之间的创建和删除,就是当路由切换的时候,HTML文件依然是那个文件,只是每次往某个坑比如id=app的div里填的东西不一样.
传统:前端由多个页面组成,后端负责组织数据、实现路由、甚至生成页面内容;前端后端其实是混杂一起的;
当前:前端由单个页面或者少量页面构成(Single Page Application),前端框架负责组织路由,切换页面内容(一般将页面拆分成组件/Componet),后端只负责提供 API 服务并收发数据;
这样前后端就基本分离解耦了。
一.hash路由
我们知道a标签一般拿来跳转路由的,但当a标签加上#时,是不会发生跳转的, 同时触发个window.onhashchange事件或者用window.addEventListener('hashchange', handleHashChange);来监听,当监听到之后对html内容修改
前端hash路由 复制代码
1.当我们点击a标签(并且hash变化)或者通过浏览器回退(或通过js调用history.back()或者history.go(-1)),前进(或者history.forward()或者history.go(1)),都会触发hashchange事件
2.刷新或第一次进入是不会触发的,所以我们在页面onload之后,手动调用了一次
二.通过history API实现
MDN上对
popstate的说明 1.只有在做出浏览器动作时,才会触发 popstate
事件,如用户点击浏览器的回退按钮(或者在Javascript代码中调用history.back()),
前进(或者history.forward()或者history.go(1)) 2.刷新或第一次进入不一定会触发popstate事件(不同的浏览器在加载页面时处理popstate事件的形式存在差异。页面加载时Chrome和Safari通常会触发(emit )popstate事件,但Firefox则不会。),所以我们可能需要手动调用一次
3.对于a标签,我们写的是正常路由,页面会跳转,必须阻止a标签默认行为,然后我们需要通过 history.pushState或者 history.replaceState修改title,url,并且存储历史记录
注意history.pushState或者 history.replaceState不会触发popstate事件,所以需要手动去修改html的内容
4.history.pushstate有安全限制,其中之一是不允许应用推动跨url-s历史起源;服务器ip的端口不同和直接在电脑本地运行的html都会报错,如下图:
为了测试该功能,我用webpack+webpack-dev-server 简单搭了个本地开发服务
test 复制代码