…续前缘
上一篇文章只是作为本文的对比, 本文重点是原生JS仿写路由
既然是仿写, 那么结构自然要基本一样咯
index.html
<!DOCTYPE html >
<html >
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<script type="text/javascript" src="js/main.js" ></script>
<title>native route</title>
</head>
<body >
<!-- 路由标签 -->
<ul>
<li><a href="#/test">test</a></li>
<li><a href="#/dev">dev</a></li>
<li><a href="#/others">others</a></li>
</ul>
<!-- 路由展示区 -->
<div id="route"></div>
</body>
</html>
其实在上周以前, 我根本不知道路由的原理, 直到上周某一天, 闲着无聊, 把上篇文章里面的元素挨个审查了一遍, 然后惊喜就来了…
或许你们会以为这没有什么, 但是当你发现meta
和title
标签, 如果再补上HTML
和body
标签, 这不就是一个完整的页面吗?
很巧的是, 我知道ajax不仅可以用来做后台数据请求, 还能请求html
或者jsp
等页面静态化后的全部数据. 至于为什么会“丢失”掉html
和body
两个标签, 自己试试不就知道咯.
想到就做, 于是写了一些JS—window
对象有一个hashchange
事件, 每当页面地址的hash
值变化时, 就会触发hashchange
这个事件. 至于什么是hash
值, 你可以把window.location
这个对象打印出来, 实时监控它, 那你就知道啦
//route路由
window.addEventListener("hashchange", function(data){
console.log(data);
var route = window.location.hash.split("#")[1];
switch(route){
case "/test":
var xhr = new XMLHttpRequest();
xhr.open("get", "route/test.html", true);
xhr.onreadystatechange = function(){
if (xhr.readyState==4 && xhr.status==200){
document.getElementById("route").innerHTML = xhr.responseText;
}
}
xhr.send(null);
break;
case "/dev":
var xhr = new XMLHttpRequest();
xhr.open("get", "route/dev.html", true);
xhr.onreadystatechange = function(){
if (xhr.readyState==4 && xhr.status==200){
document.getElementById("route").innerHTML = xhr.responseText;
}
}
xhr.send(null);
break;
default:
var xhr = new XMLHttpRequest();
xhr.open("get", "route/default.html", true);
xhr.onreadystatechange = function(){
if (xhr.readyState==4 && xhr.status==200){
document.getElementById("route").innerHTML = xhr.responseText;
}
}
xhr.send(null);
break;
}
});
紧接着就是route
文件夹下面的三个html
文件
default.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>default</title>
</head>
<body>
<h1>defaultPage</h1>
</body>
</html>
dev.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>dev</title>
</head>
<body>
<h1>developmentEnviroment</h1>
</body>
</html>
test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<body>
<h1>testEnviroment</h1>
</body>
</html>
到此为止, 原生JS路由就写完了…但是, JS文件不觉得很是复杂吗, 所以我们把ajax函数提取出来精简
// ajax请求
function xhrPage(url){
var xhr = new XMLHttpRequest();
xhr.open("get", url, true);
xhr.onreadystatechange = function(){
if (xhr.readyState==4 && xhr.status==200){
document.getElementById("route").innerHTML = xhr.responseText;
}
}
xhr.send(null);
}
//route路由
window.addEventListener("hashchange", function(data){
console.log(data);
var route = window.location.hash.split("#")[1];
switch(route){
case "/test":
xhrPage("route/test.html");
break;
case "/dev":
xhrPage("route/dev.html");
break;
default:
xhrPage("route/default.html");
break;
}
});
这样看着是不是很清爽? 而这也符合函数式编程的思想(还有一个是面向对象编程:OOP无非是把函数写到对象的一个属性中)—能避免大量代码冗余以及使结构清晰, 也利于复用. 现在如果再点击路由标签, 会发现下面能显示相应的页面
而不出所料, 原生加载的文档与ng框架加载出来的页面是一样的. 也就是说—至少这个思想没问题, 只是实现方法不同而已
测试之后, 或许你又会发现一个问题, 在ng中, 页面一进来就会呈现路由加载后的情形, 而自己写的只有在点击后才会出现路由, 所以再进行改进(猜测: 可能是ng中用了window.location.href这个属性)
// ajax请求
function xhrPage(url){
var xhr = new XMLHttpRequest();
xhr.open("get", url, true);
xhr.onreadystatechange = function(){
if (xhr.readyState==4 && xhr.status==200){
document.getElementById("route").innerHTML = xhr.responseText;
}
}
xhr.send(null);
}
function hashChange(route){
switch(route){
case "/test":
xhrPage("route/test.html");
break;
case "/dev":
xhrPage("route/dev.html");
break;
default:
xhrPage("route/default.html");
break;
}
}
//route路由
window.addEventListener("hashchange", function(data){
console.log(data);
var route = window.location.hash.split("#")[1];
hashChange(route);
});
window.addEventListener("load", function(){
var _route = window.location.href.split("#")[1];
hashChange(_route);
});
这样改进代码之后的确实现了进来就加载路由
好了, 再回过来解释问题: 没有html和body
因为浏览器有自动补全(删除)机制, html
和body
在一个document里面只能加载一次, 其余的都会被浏览器智能删掉. 可以通过DevTools的sources面板来查看.
想必vue的路由加载机制与此出入不大…
如果文中有什么不对的地方, 敬请指正.
打完, 收工.