项目情况:项目未做 前后端分离(目前前端和后端同一个项目);
项目类型:.Net5 MVC ;
路由需求:每个页面可以独立访问 ,且每个页面可以局部加载,比如:A页面中可以加载B页面,做为A页面的子页面,或A页面可以跳转到B页面并保持A页面的状态不变(即从B页面反回A页面后A页面的数据仍然存在,可继续使用),不得使用location跳转。
解决方案:
市面上已知的路由插件没有可适用本项目的,因此根据项目需求,从0开发此插件。
路由效果:页面跳转-局部加载
直接访问某个页面-完整加载
插件代码:
/**
* 每人页面最外层的类是.page
*/
$(function () {
var pageManager = {
$container: $('#container'),
home: { id: "home", title: "首页", url: "/c/wugee/index" },
_pageStack: [],//主子页面路径
_pageOpened: [],//已开打的页面
init: function () {
var _this = this;
$(window).on('hashchange', function () {
var state = history.state || {};
var id = location.hash.indexOf('#') === 0 ? location.hash.replace("#", "") : '#';
let page = _this._pageOpened.find(f => f.id == id);
if (!page) {
//找不到页面时默认到首页
page = _this.home;
}
var opened = _this._pageStack.some(s => s.url == page.url);
if (opened || page.url == _this.home.url) {
_this._back(page);
/* _this._back(page);*/
} else {
_this._showPage(page);
}
});
//打开首页或指定的页面
//$("#" + _this.home.id).data("url", _this.home.url)
//_this._pageOpened.push(_this.home);
//_this._pageStack.push(_this.home);
if (location.hash.length > 1 && location.hash.startsWith("#")) {
location.href=_this.home.url;
}
return this;
},
redirect: function () {
},
_back: function (page) {
var _this = this;
var lastPage = this._pageStack.pop();
if (!lastPage) return;
$("#" + page.id).parent().show();
let $lastPage = $("#" + lastPage.id).parent().addClass("slideOut");
$lastPage.on('animationend webkitAnimationEnd', function () {
$lastPage.unbind("animationend webkitAnimationEnd");
_this._defaultPage = page;
});
},
go: function (p) {
let _this = this;
let page = {};
if (typeof p == "object") {
page = p;
} else {
page ={url: p,title: "",id: "",};
}
//转换url为小写
page.url = page.url.toLowerCase();
let oldPage = _this._pageOpened.find(o =>o.url == page.url);
if (oldPage) {
//表示页面已打开过
location.hash = oldPage.id;
} else {
var loadingPage = null;
loadingPage= weui.loading('跳转中', {className: 'custom-classname'});
//删除可以已经存在的页面
let oldPage = $("#" + page.id);
if (oldPage.length>0) {
oldPage.parent().remove();
}
$.ajax({
url: page.url,
dataType: "html",
headers: {
Accept: "text/html, */*; q=0.01",
//表示不加载页面模板
partial:true,
},
cache: false,
data: {},
contentType: "text/html; charset=utf-8",
type: "get",
//async: false
success: function (html) {
let $page = $(html).data("url",page.url);
_this.$container.append($page);
let pageId = $page.find("div:first").attr("id");
//删除url不同 且是同一个页面的
//let thisPageExists = _this._pageOpened.findIndex(f => f.id == pageId);
//thisPageExists && _this._pageOpened.splice(thisPageExists, 1);
page.id = pageId;
_this._pageOpened.push(page);
location.hash = page.id;
},
error: function (XmlHttpRequest, textStatus, errorText) {
console.log("错误", textStatus, errorText);
},
complete: function () {
if (loadingPage) {
loadingPage.hide(function () { });
}
}
});
}
},
_showPage(page) {
let $page = $("#" + page.id).parent();
$page.show().addClass('slideIn').attr('tabindex', '-1').trigger('focus');
$page.removeClass("slideOut").on('animationend webkitAnimationEnd', function () {
$page.removeClass('slideIn').addClass('js_show');
$page.siblings().hide().attr('aria-hidden', 'true');
$page.unbind("animationend webkitAnimationEnd");
});
this._pageStack.push(page);
this._defaultPage = page;
}
};
function fastClick(){
var supportTouch = function(){
try {
document.createEvent("TouchEvent");
return true;
} catch (e) {
return false;
}
}();
var _old$On = $.fn.on;
$.fn.on = function(){
if(/click/.test(arguments[0]) && typeof arguments[1] == 'function' && supportTouch){ // 只扩展支持touch的当前元素的click事件
var touchStartY, callback = arguments[1];
_old$On.apply(this, ['touchstart', function(e){
touchStartY = e.changedTouches[0].clientY;
}]);
_old$On.apply(this, ['touchend', function(e){
if (Math.abs(e.changedTouches[0].clientY - touchStartY) > 10) return;
e.preventDefault();
callback.apply(this, [e]);
}]);
}else{
_old$On.apply(this, arguments);
}
return this;
};
}
function preload(){
$(window).on("load", function(){
var imgList = [
//"./images/layers/content.png",
];
for (var i = 0, len = imgList.length; i < len; ++i) {
new Image().src = imgList[i];
}
});
}
function androidInputBugFix(){
if (/Android/gi.test(navigator.userAgent)) {
window.addEventListener('resize', function () {
if (document.activeElement.tagName == 'INPUT' || document.activeElement.tagName == 'TEXTAREA') {
window.setTimeout(function () {
document.activeElement.scrollIntoViewIfNeeded();
}, 0);
}
})
}
}
function init(){
preload();
fastClick();
androidInputBugFix();
window.pageManager = pageManager.init();
}
init();
});