单页应用很火。翻开知乎,看到“单页应用的好处”,到处可见:前后端分离等等云云。
它是个啥?《单页Web应用----JavaScript从前端到后端》赫然写着,“单页应用指的是在浏览器中运行的应用,在使用期间页面不会重新加载”。
举个例子,传统web的导航条,点一个菜单,啪发送一个请求给服务器,然后展示一个新页面;然后点另外一个菜单,啪又发送一个请求个服务器,然后又展示一个新页面。这页面是重新加载的,是崭新的。但是【单页应用】不会,你点击一个导航条,它甚至都不会发送请求给服务器,只是默默的局部刷新一下内容页(比如AngularJS的路由)。
这是怎样实现的?抛开一堆花里胡哨的JS库不看,就从它们的根---JavaScript看起。JS语言的两个重点:1.DOM操作 2.Ajax请求。
00:我们先最猥琐的方式实现一个单页应用:
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<script type="text/javascript">
var pages = {1:"这是页面1",2:"这是页面2"};
window.onload = function(){
document.getElementById("content").innerHTML = pages[1];
}
function clickPage(id){
document.getElementById("content").innerHTML = pages[id];
}
</script>
</head>
<body>
<div style="width:100%;height:80px;">
<a href="javascript:clickPage(1)">页面1</a>
<a href="javascript:clickPage(2)">页面2</a>
</div>
<div id="content">
</div>
</body>
</html>
其实就是根据点击的菜单,用innerHTML将页面嵌入到div中;pages中的内容可以发散思维啊,就是可以填入巨复杂的html串,里面包含js进行ajax请求来刷新自己/展示数据等等。这就是一个单页应用,只不过写代码的人应该是相当痛苦。
01:然后就有人说,把每个页面的html独立到单独的代码文件中吧。不要直接放在字符串中,要不然太痛苦了。然后就有了下面的一种实现:
index1.html
index2.html
里面各种html/js代码,利用ajax请求来读取数据发送请求等等。
然后index.html这样实现:
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"?>
<script type="text/javascript" src="jquery-1.10.2.js"></script>
<script type="text/javascript">
jQuery(document).ready(function(){
jQuery("#content").load("index1.html");
});
function clickPage(id){
jQuery("#content").load("index"+id+".html");
}
</script>
</head>
<body>
<div style="width:100%;height:80px;">
<a href="javascript:clickPage(1)">页面1</a>
<a href="javascript:clickPage(2)">页面2</a>
</div>
<div id="content">
</div>
</body>
</html>
是不是清爽了很多?导航切换时也只是局部刷新了content的内容,没有重新加载页面。
02:有人说,还是太复杂了,再让它清爽一点吧。于是就有了类似下面的实现:
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"?>
<script type="text/javascript" src="jquery-1.10.2.js"></script>
<script type="text/javascript">
jQuery(document).ready(function(){
jQuery("#content").load("index1.html");
jQuery("a").bind("click",function(event){
if(jQuery(this).attr("href")=="#page1"){
jQuery("#content").load("index1.html");
}else if(jQuery(this).attr("href")=="#page2"){
jQuery("#content").load("index2.html");
}
event.stopPropagation();
});
});
</script>
</head>
<body>
<div style="width:100%;height:80px;">
<a href="#page1">页面1</a>
<a href="#page2">页面2</a>
</div>
<div id="content">
</div>
</body>
</html>
03.这时又有人说了,我甚至不希望关心点击导航时,页面是如何局部刷新的。我只期望指定某个导航对应哪个页面即可。OK,那我们就对它的方法进行一下抽象吧。
route.js
function routeProvider(menu){
var dict = Array();
for(var key in menu){
dict[key] = menu[key]["template"];
}
jQuery("a").bind("click",function(event){
jQuery("#content").load(dict[jQuery(this).attr("href")]);
event.stopPropagation();
});
}
index.html的实现:
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"?>
<script type="text/javascript" src="jquery-1.10.2.js"></script>
<script type="text/javascript" src="route.js"></script>
<script type="text/javascript">
jQuery(document).ready(function(){
jQuery("#content").load("index1.html");
routeProvider({
"#page1":{"template":"index1.html"},
"#page2":{"template":"index2.html"},
});
});
</script>
</head>
<body>
<div style="width:100%;height:80px;">
<a href="#page1">页面1</a>
<a href="#page2">页面2</a>
</div>
<div id="content">
</div>
</body>
</html>
OK,你甚至可以沿着这个思路,继续封装,最后实现一个类似AngularJS路由功能类似的东东。
框架API是我非常不愿意记忆的API之一,我觉得毫无意义,只是他人提出来的理念,让你照着他的意思玩。太耗费大脑的存储空间了,而且现在的JS库也实在太多了。