进击的前端路由

今天立项,最近准备学习前端路由。感受一下真正的单页面开发与加强js的掌握。嗯,是这样的,我要尝试自己做一个路由的哦!(还有今天开始晚上跑步,如果可以再刷一下leecode)
2017/2/18更新回家过了个年,胖的要死,先发一个简易的前端路由吧,其他的都先删了吧。最近在看书,偶尔刷题,也没有更新博客了,总觉得没什么好更新的,对了最近在找工作!可以联系我邮箱置顶!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
(function(window){
//html5API
var support = history.pushState ? "html5" : ("onhashchange" in window ? "hash" : "pass");
var currentUrl = "";
var cache = {
key: function(url){
return "x-pjax[" + url + "]";
},
get: function(url){
var value = sessionStorage.getItem(cache.key(url));
return value && JSON.parse(value);
},
set: function(url, value){
try{
sessionStorage.setItem(cache.key(url), JSON.stringify(value));
} catch (e){
console.log("太大了boy");
}
},
clear: function(){
var i = sessionStorage.length;
while(i--){
var key = sessionStorage.key(i);
if(key.indexOf("x-pjax") > -1){
sessionStorage.removeItem(key);
}
}
}
};

var event = function(self){
var pjax = self;
this.popstate = function(){
pjax.fnb = true;
pjax.jump(location.href, null, null);
};
this.hashchange = function(){
if(!pjax.fnb) return;
pjax.jump(location.href.replace("#/", ""), null, null);
};
this.click = function(e){
var element = e.target || e.srcElement;
var url = element.href;
currentUrl = location.href;
var strUrl = url.split("/").slice(3);
strUrl = "/" + strUrl.join("/");
//过滤空值
if(url === undefined || url === ""){
return ;
}else if(pjax.routers && !(strUrl in pjax.routers)){
return ;
}
e.preventDefault ? e.preventDefault() : (window.event.returnValue = false);
console.log("shifouttiaozhuan");
return false;
var data = encodeURI(element.getAttribute("title"));
pjax.fnb = false;
pjax.jump(url, data, null);
};
this.bindEvent = function(){
var eventSelf = this;
if(support === "html5"){
window.addEventListener("popstate", eventSelf.popstate);
var nav = document.getElementById("nav");
nav.addEventListener("click", eventSelf.click);
}else{
window.attachEvent("onhashchange", eventSelf.hashchange);
var nav = document.getElementById("nav");
nav.attachEvent("onclick", eventSelf.click);
}
};
};

var pjax = window.pjax = function(routers){
if(!(this instanceof pjax)){
return new pjax(routers);
}
//表示当前操作是否由前进和后退触发
this.event = new event(this);
this.fnb = false;
this.routers = routers;
};
//显示新页面内容
pjax.prototype.show = function(title, html, selector){
document.title = title;
selector.innerHTML = html;
};
//跳转到指定页面
pjax.prototype.jump = function(url, data, callback){
//如果是由前进或后退触发,则试着从缓存中获取数据
if(this.fnb){
var strUrl = routerUrl(url);
var containerId = self.routers[strUrl].containerId,
callback = self.routers[strUrl].callback;
var container = document.querySelector("#"+containerId);
var value = cache.get(url);
if(value !== null){
this.show(value.title, value.html, container);
if(callback){
callback();
}
return;
}
}

var self = this;
//ajax发送请求并且渲染
jumpXhr(self, url, data);
};
pjax.prototype.init = function(){
this.event.bindEvent();
};
pjax.prototype.configure = function(routers, options){
// this.recursion = options.recursion;
var data = routersInOrder(routers, "", {}, []);
this.routers = data.newRouter; //存储所有路径对应的映射结果
this.methodRouters = routersSort(data.routersName); //存储所有的路径名字
};
function Ajax(url, data, selector){

}
function htmlRender(url, container){
var data = Ajax(url);
container.innerHTML = data.html;
}
function JsRender(url){
var ajaxFlag = true;
var scripts = document.querySelectorAll("script");
scripts.forEach(function (currentValue, index){
if(currentValue.src === url){
ajaxFlag = false;
return ;
}
});
if(ajaxFlag){
var script = document.createElement("script");
script.language = "javascript";
script.src = url;
document.body.appendChild(script);
}
}
function jumpXhr(self, url, data){
var strUrl = routerUrl(url);
var containerId = self.routers[strUrl].containerId,
htmlUrl = url + "/" + self.routers[strUrl].htmlurl,
controllerUrl = url + "/" + self.routers[strUrl].controller,
callback = self.routers[strUrl].callback;
console.log(self.routers[strUrl]);
var container = document.querySelector("#"+containerId);

var xhr = new XMLHttpRequest();
xhr.open("get", htmlUrl, true);
xhr.setRequestHeader("X-PJAX", "true");
xhr.setRequestHeader("X-PJAX-TITLE", data);
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
xhr.onreadystatechange = function() {
var self = this;
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
var html = xhr.responseText;
var title = xhr.getResponseHeader("X-PJAX-TITLE");
if (title === null) {
title = document.title;
} else {
title = decodeURI(title);
}
}
// selector.innerHTML = htmlOrJs;
self.show(title, html, container);
JsRender(controllerUrl);
callback();
//不是前进和后退触发的
if(!self.fnb){
//修改URL,URL地址栏会变换
if(support === "html5"){
history.pushState(null, null, url);
}else{
var path = url.replace(location.protocol + "//" + location.host, "");
location.hash = path;
}
//添加到缓存
cache.set(url, {
title: title,
html: html
});
}else{
console.log("请求失败");
}
self.fnb = true;
}

}.bind(self);

xhr.send(null);
//这里面好像bind之类的闭包用的太多了好像

}

function initRegexps (route){ //根据路由字段生成相应的正则表达式
route = route.replace(/[/,.+\-?$#{}\[\]]/g, '\\$&') //然后把所有的正则表达式匹配传入的url如果匹配就触发函数
.replace(/\((.*?)\)/g, '(?:$1)?')
.replace(/(\/\w?:\w+)+/g, '\/([^/]+)')
.replace(/\*\w*/g, '([^?]*?)');
console.log(route);
return new RegExp('^' + route + '$');
}

function dispath(url, self){ //根据url触发沿途的所有回调
var urlArray = url.split("/");
for(var len1 = urlArray.length, i = len-1; i > 0; i--){
urlArray[i] = urlArray.shift(len-1-i).join("/");
}
if(self.recursion){ //向后递归
var j = 0;
while(urlArray[j]){
if(urlArray[i] in self.methodRouters){// 这里应该使用正则匹配对不起
self.methodRouters[urlArray[j]].call(self, urlArray[j]);
}
j++;
}
}else{
var j = len-1;
while(urlArray[j]){
if(urlArray[i] in self.methodRouters){// 这里应该使用正则匹配对不起
self.methodRouters[urlArray[j]].call(self, urlArray[j]);
}
j--;
}
}
}
function routersSort(arr){
if(arr.length <= 1){return arr;}
var left = [], right = [];
var a = Math.floor(arr.length/2);
var ai=arr.splice(a,1)[0]; //基准必须从原数组删除,否则陷入循环
for(var i = 0, len = arr.length; i < len; i++){
if(arr[i] > ai){ //修改了储存方式
right.push(arr[i]);
}else{
left.push(arr[i]);
}
}
return routersSort(left).concat([ai],routersSort(right));
}
function routersInOrder(routers, name, newRouter, routersName){
if(typeof name === "undefined"){
name = "";
}
for( var i in routers){
if(routers[i] && (typeof routers[i].containerId === "undefined")){
routersInOrder(routers[i], name + i, newRouter, routersName);
}else if(routers[i] && (typeof routers[i].callback === "function")){
newRouter[name + i] = routers[i];
routersName.push(name + i);
}
}
return {
newRouter: newRouter,
routersName: routersName
};
}
function routerUrl(url){
var strUrl = url.split("/").slice(3);
strUrl = "/" + strUrl.join("/");
return strUrl;
}

})(window);