雨霖铃
2025-11-25 01:07:46 +08:00
parent a4c331bd8b
commit ed6053473d
9 changed files with 400 additions and 143 deletions
+229
View File
@@ -0,0 +1,229 @@
import {
RouteUtils,
addClass,
removeClass,
hasClass,
getParamsUrl,
closure,
genKey,
} from '../utils/routeUtils.js';
class Router {
constructor() {
// 路由表
this.routes = {};
// 路由跳转前执行
this.beforeFun = null;
// 路由跳转后执行
this.afterFun = null;
// 路由挂载点
this.routerViewId = 'router-view';
// 路由重定向hash
this.redirectRoute = null;
// 多级页面缓存
this.stackPages = true;
// 路由遍历
this.routerMap = [];
// 路由状态
this.historyFlag = '';
// 路由历史
this.history = [];
// 动画名称
this.animationName = 'fade';
}
init(config) {
this.routerMap = config ? config.routers : this.routerMap;
this.routerViewId = config ? config.routerViewId : this.routerViewId;
this.stackPages = config ? config.stackPages : this.stackPages;
if (!this.routerMap.length) {
let selector = this.routerViewId + '.page';
let pages = document.querySelectorAll(selector);
for (let i = 0; i < pages.length; i++) {
let page = pages[i];
let hash = page.getAttribute('hash');
let name = hash.substring(1);
this.routerMap.push({
name: name,
path: hash,
callback: closure(name),
});
}
}
window.linkTo = (path) => {
console.log('path', path);
if (path.indexOf('?') !== -1) {
window.location.hash = path + '&key=' + genKey();
} else {
window.location.hash = path + '?key=' + genKey();
}
};
window.addEventListener(
'load',
function (event) {
this.historyChange(event);
},
false
);
}
/**
* 路由历史纪录变化
* @param {*} event
*/
historyChange(event) {
const currentHash = getParamsUrl();
const nameString = 'router-' + this.routerViewId + '-history';
this.history = window.sessionStorage[nameString]
? JSON.parse(window.sessionStorage[nameString])
: [];
let back = false,
refresh = false,
forward = false,
index = 0,
len = this.history.length;
for (let i = 0; i < len; i++) {
let h = this.history[i];
if (h.hash === currentHash.path && h.key === currentHash.query.key) {
index = i;
if (i === len - 1) {
refresh = true;
} else {
back = true;
}
break;
} else {
forward = true;
}
}
if (back) {
this.historyFlag = 'back';
this.history.length = index + 1;
} else if (refresh) {
this.historyFlag = 'refresh';
} else {
this.historyFlag = 'forward';
this.history.push({
key: currentHash.query.key,
hash: currentHash.path,
query: currentHash.query,
});
}
console.log('historyFlag', this.historyFlag);
if (!this.stackPages) {
this.historyFlag = 'forward';
}
window.sessionStorage[nameString] = JSON.stringify(this.history);
this.urlChange();
}
changeView(currentHash) {
const pages = document.querySelectorAll('.page');
const previousPage = document.querySelector('.' + this.routerViewId + ' .page.active');
let currentPage = null;
let currentHash = null;
for (let i = 0; i < pages.length; i++) {
let page = pages[i];
let hash = page.getAttribute('hash');
page.setAttribute('class', 'page');
if (hash === currentHash.path) {
currentHash = hash;
currentPage = page;
}
}
const enterName = 'enter-' + this.animationName;
const leaveName = 'leave-' + this.animationName;
if (this.historyFlag === 'back') {
addClass(currentPage, 'current');
if (previousPage) {
addClass(previousPage, leaveName);
}
setTimeout(() => {
if (previousPage) {
removeClass(previousPage, leaveName);
}
}, 300);
} else if (this.historyFlag === 'forward' || this.historyFlag === 'refresh') {
if (previousPage) {
addClass(previousPage, leaveName);
}
addClass(currentPage, enterName);
setTimeout(() => {
if (previousPage) {
removeClass(previousPage, leaveName);
}
addClass(currentPage, enterName);
removeClass(currentPage, 'current');
}, 300);
currentPage.scrollTop = 0;
this.routes[currentHash].callback ? this.routes[currentHash].callback() : null;
}
this.afterFun ? this.afterFun(currentHash) : null;
}
urlChange() {
const currentHash = getParamsUrl();
if (this.routes[currentHash.path]) {
if (this.beforeFun) {
this.beforeFun({
to: {
path: currentHash.path,
query: currentHash.query,
},
next: () => {
this.changeView(currentHash);
},
});
} else {
this.changeView(currentHash);
}
} else {
location.hash = this.redirectRoute;
}
}
map() {
for (let i = 0; i < this.routerMap.length; i++) {
let route = this.routerMap[i];
if (route.name === 'redirect') {
this.redirectRoute = route.path;
} else {
this.redirectRoute = this.routerMap[0].path;
}
let newPath = route.path;
let path = newPath.repalce(/\s+/g, '');
this.routes[path] = {
callback: route.callback,
};
}
}
beforeEach(callback) {
if (Object.prototype.toString.call(callback) === '[object Function]') {
this.beforeFun = callback;
} else {
console.trace('beforeEach callback must be a function');
}
}
afterEach(callback) {
if (Object.prototype.toString.call(callback) === '[object Function]') {
this.afterFun = callback;
} else {
console.trace('afterEach callback must be a function');
}
}
}