js实现SPA单页面应用路由
js实现SPA单页面应用路由
router.js
/**
* @description SPA路由
* @author https://github.com/kliuj
* @use new Router([{},{},...]);
*/
var util = {
//获取路由的路径和详细参数
getParamsUrl: function () {
var hashDeatail = location.hash.split("?"),
hashName = hashDeatail[0].split("#")[1], //路由地址
params = hashDeatail[1] ? hashDeatail[1].split("&") : [], //参数内容
query = {};
for (var i = 0; i < params.length; i++) {
var item = params[i].split("=");
query[item[0]] = item[1]
}
return {
path: hashName,
query: query
}
}
}
function Router(route) {
this.route = route || []; // 路由集合
this.routers = {}; // 保存注册的所有路由
this.beforeFun = undefined;
this.afterFun = undefined;
this.init(route);
}
Router.prototype = {
init: function (route) {
var self = this;
//页面加载匹配路由
window.addEventListener('load', function () {
self.urlChange()
})
//路由切换
window.addEventListener('hashchange', function () {
self.urlChange()
})
//异步引入js通过回调传递参数
window.SPA_RESOLVE_INIT = null;
if (!route.length) {
console.trace('路由注册不能为空');
}
route.forEach(item => {
self.register(item.path, transition => {
self.asyncFun(item.component, transition);
})
})
},
refresh: function (currentHash) {
var self = this;
if (self.beforeFun) {
self.beforeFun({
to: {
path: currentHash.path,
query: currentHash.query
},
next: function () {
self.routers[currentHash.path].callback.call(self, currentHash)
}
})
} else {
self.routers[currentHash.path].callback.call(self, currentHash)
}
},
//路由处理
urlChange: function () {
var currentHash = util.getParamsUrl();
console.log(this.routers);
if (this.routers[currentHash.path]) {
this.refresh(currentHash)
} else {
//不存在的地址重定向到首页
location.hash = '/'
}
},
//单层路由注册
register: function (path, callback) {
path = path.replace(/\s*/g, ""); //过滤空格
if (callback && Object.prototype.toString.call(callback) === '[object Function]') {
this.routers[path] = {
callback: callback, //回调
fn: null //存储异步文件状态
}
} else {
console.trace('注册' + path + '地址需要提供正确的的注册回调')
}
},
//切换之前一些处理
beforeEach: function (callback) {
if (Object.prototype.toString.call(callback) === '[object Function]') {
this.beforeFun = callback;
} else {
console.trace('路由切换前钩子函数不正确')
}
},
//切换成功之后
afterEach: function (callback) {
if (Object.prototype.toString.call(callback) === '[object Function]') {
this.afterFun = callback;
} else {
console.trace('路由切换后回调函数不正确')
}
},
//路由异步懒加载js文件
asyncFun: function (file, transition) {
var self = this;
if (self.routers[transition.path].fn) {
self.afterFun && self.afterFun(transition)
self.routers[transition.path].fn(transition)
} else {
console.log("开始异步下载js文件" + file)
var _body = document.getElementsByTagName('body')[0];
var scriptEle = document.createElement('script');
scriptEle.type = 'text/javascript';
scriptEle.src = file;
scriptEle.async = true;
SPA_RESOLVE_INIT = null;
scriptEle.onload = function () {
console.log('下载' + file + '完成')
self.afterFun && self.afterFun(transition)
self.routers[transition.path].fn = SPA_RESOLVE_INIT;
self.routers[transition.path].fn(transition)
}
_body.appendChild(scriptEle);
}
},
//同步操作
syncFun: function (callback, transition) {
this.afterFun && this.afterFun(transition)
callback && callback(transition)
}
}
test.html
<!DOCTYPE HTML>
<html>
<head>
<title>test hash route</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script type="text/javascript" src="./router.js"></script>
<style type="text/css">
body {
font: 10.5pt arial;
color: #4d4d4d;
line-height: 150%;
width: 90%;
}
a {
font-size: 16px;padding: 10px
}
#content{
font-size:20px;font-weight:bold;padding: 20px
}
</style>
</head>
<body>
<a href="#/index?index=1">异步加载首页</a>
<a href="#/list?list=1">异步加载列表页</a>
<a href="#/detail?detail=1">异步加载详情页</a>
<a href="#/detail2?detail=2">同步加载详情页</a>
<div id="content">
<p style="color:#333">默认首页内容</p>
</div>
<script type="text/javascript" >
const routers = [
{
name: 'index',
path: '/index',
component: 'js/index.js'
},
{
name: 'list',
path: '/list',
component: 'js/list.js'
},
{
name: 'detail',
path: '/detail',
component: 'js/detail.js'
},
{
name: 'detail2',
path: '/detail2',
component: 'js/detail.js'
},
]
window.$router = new Router(routers);
</script>
</body>
</html>
Js/index.js
SPA_RESOLVE_INIT = function(transition) {
document.getElementById("content").innerHTML = '<p style="color:#099fde;">当前异步渲染首页'+ JSON.stringify(transition) +'</p>'
console.log("首页回调" + JSON.stringify(transition))
}
js/list.js
SPA_RESOLVE_INIT = function(transition) {
document.getElementById("content").innerHTML = '<p style="color:#F8C545;">当前异步渲染列表页'+ JSON.stringify(transition) +'</p>'
console.log("首页回调" + JSON.stringify(transition))
}
js/detail.js
SPA_RESOLVE_INIT = function(transition) {
document.getElementById("content").innerHTML = '<p style="color:red;">当前异步渲染详情页'+ JSON.stringify(transition) +'</p>'
console.log("首页回调" + JSON.stringify(transition))
}
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!