知乎上有人问「比一我的吃火锅更寂寞的是什么?」我想回答「一我的写先后端,却要装成一个团队。」html
咱们在前期开发的过程当中,更可能是一我的单打独斗,由于是本身一我的,能够把代码写的很随意,也不用注意什么工程化的东西;但做为一个有追求的程序员,不能为将来的本身挖坑,坚定走前端工程化的路线。前端
虽然我是一我的,但我是一个团队。java
因此这是我本身在开发过程当中总结的一些知识,慢慢会写成一个系列吧。「单页应用」做为系列的第一篇。jquery
对于单页应用个人定义是:在浏览器地址栏输入地址以后,服务器获取到HTML文档,以后全部页面的呈现都在这份HTML文档之上进行。webpack
由于这是流行啊。即便我司对性能啥的彻底没有任何要求,我仍是强行用了单页应用,本身不努力,没人帮我学。具体有什么好处仍是坏处,若是本身没写过单页应用,即便别人说一大堆好处坏处你也仍是不懂。(这是吐槽,不用理会)git
在浏览器地址栏输入地址以后,会从服务器端下载HTML文档并开始渲染。(这个谁能看懂,谁看吧,反正我看不懂)在渲染的过程当中,解析 script 标签,外部引入的话,就发起请求获取 JavaScript 文件。
页面渲染完成,以后全部网站的内容都会在这个页面上呈现,全部的操做也只会在这个页面进行。程序员
假设咱们在浏览器输入 http://xxxx.com 的时候,服务端会返回 index.html 文档以下:github
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>demo</title> </head> <body> <div id="app"> <nav id="nav"></nav> <div id="container"></div> </div> <script src="/jquery.js"></script> <script src="/app.js"></script> </body> </html>
这里插一句为何把 script 标签放到最后?浏览器在渲染的时候会被 script 标签阻塞,影响页面的首次渲染。可能会由于 JavaScript 文件过大,等待加载时间过长(若是是外部引入),页面一直是空白。web
咱们在构建单页面应用时,大部分的内容经过 JavaScript 生成。在 app.js 中,咱们会生成一个导航:
var $nav = $('#nav') var sLi = ['home','about','article','history'].reduce(function(pre, n) { return pre + '<li><a href="/' + n + '">' + n + '</a></li>'; }, ''); var sUl = '<ul>' + sLi + '</ul>'; $nav.html(sUl);
生成以下图的导航条
以后咱们想根据导航生成不一样的页面内容:
var $container = $('#container') $('#nav ul li').on('click', function() { $container.html('这是' + $(this).find('a').text() + '区域哦') return false; })
然而现实中,咱们的页面多数是根据后端返回的数据来渲染,例如咱们的后端提供了一个接口 /api/home
, 经过这个接口能够得到数据 ["今", "天", "天", "气", "不", "错", "啊"]
,当咱们进入 home 页面的时候页面上会结合经过 api 接口获取来的数据展现新的页面:
$('#nav ul li').on('click', function() { var route = $(this).find('a').text() if('home' === route) { $.get('/api/home', function(data) { $container.html(data.join('') + '!') }) } else { $container.html('这是' + route + '区域哦') } return false; })
这是我刚接触单页应用时候比较头疼的地方。
没有路由,我就不知道你在哪儿。 --- by 我要某上头条君
经过 Ajax 能够获取服务器的数据而后再渲染到页面上,这个方法虽然交互很友好,不须要从新刷新页面就能够看到新的内容;可是有一点很差,那就是当点击导航后,浏览器地址栏的连接不会有变化,用户彻底不知道如今在哪一个页面。
不过这里有个知识点是须要你们理解的,当咱们在浏览器地址栏输入地址或者经过其余页面的外链跳转到这个页面时,整个页面都会刷新一遍,从服务器获取 HTML 文档渲染。在 JavaScript 中,能够经过 location.href 修改地址,可是这个方法和浏览器输入地址的效果是相同的,那有没有办法只修改浏览器的地址栏,而不刷新整个页面呢?
还好咱们有 HTML5 的 History Api 来解决这个问题,固然低版本的IE浏览器也能够经过 location.hash 的方法实现,hash 来解决的方法不在这里深究了。毕竟低版本浏览器已经不必支持了。
$('#nav ul li').on('click', function() { var route = $(this).find('a').text() history.pushState({ title: route }, route, route) show() return false; }) function show() { var route = window.location.pathname if('/home' === route) { $.get('/api/home', function(data) { $container.html(data.join('') + '!') }) } else { $container.html('这是' + route + '区域哦') } }
在点击导航以后,会将当前的路由体如今浏览器的地址中。不过,浏览器地址变化以后,点击前进后退,页面并不会有什么变化。咱们能够经过对 window 对象绑定 popstate 方法来解决
window.addEventListener("popstate", show);
传统的网站,用户一般输入具体 url 来进入相关页面,例如:咱们进入 GitHub 本身的主页是输入的是 github.com/user
;可是单页面应用,咱们的页面都是在一个空的 html文档中经过 JavaScript 生成的页面,因此服务器不能经过url来返回具体的页面(实际上是能够的,同构
,不在这里展开),那么应该怎么作呢?
对于服务器来讲,不用管那么多,当用户输入 url 以后,只要 url 符合必定的规则(例如:请求头的 accept 是 'text/html' 或者全部非 /api/ 开头的 url 等),都返回默认的 index.html。JavaScript 能够经过当前的路由来渲染:
function show() { var route = window.location.pathname if('/home' === route) { $.get('/api/home', function(data) { $container.html(data.join('') + '!') }) } else if('/' !== route) { $container.html('这是' + route + '区域哦') } } // 初始化的时候就调用 show()
到此为止,单页面的应用就算介绍完了。理解了单页面应用的原理,对于最近流行的 Angular
, React
, Vue
之类库或框架的才算刚刚开始。
若是以为本文对你有帮助的话,就点个推荐呗。
下一篇我会介绍 一我的的团队(二)--- 神兵利器之 webpack 和 webpack-dev-server