给自己的博客添加无刷新跳转
注意事项:innerHTML之后的代码,是不会运行其中的js的。需要自己解析里面的js
// 处理浏览器历史记录
let oldUrl = location.href;
window.addEventListener('popstate', function (e) {
let href = location.href;
if (href.replace(oldUrl, '').startsWith('#') || oldUrl.replace(href, '').startsWith('#')) {
oldUrl = href;
} else {
if (href.startsWith(location.origin)) {
noRefreshJump(href, 'change');
}
}
});
document.addEventListener('click', e => {
// 禁止链接跳转行为
e.preventDefault();
let href = e.target.href;
let target = e.target.target;
// 处理被点击的标签非标链接本身的情况
if (!href) {
href = e.target.closest('a')?.href;
target = e.target.closest('a')?.target;
}
// 只处理本站链接。
if (href && href.startsWith(location.origin)) {
if (target === '_blank') {
window.open(location.origin + href, '_blank');
} else {
noRefreshJump(href, 'click');
}
}
});
function noRefreshJump(href, type) {
let oldMain = document.getElementById('main');
let body = document.body;
// 隐藏侧边栏
document.querySelector('.mdui-overlay-show')?.click();
// 请求页面数据
loading();
fetch(href).then(res => res.text()).then(res => {
// 识别标题
let title = res.match(/<title>([^<>]+?)<\/title>/)?.[1];
// 识别正文
let mainString = res.match(/<main[^<>]*>([\s\S]+?)<\/main>/)?.[1];
if (mainString) {
let scripts = mainString.match(/<script[^<>]*>[\s\S]*?<\/script>/ig) || [];
scripts.forEach((item, index) => {
mainString = mainString.replace(item, '');
});
oldMain.innerHTML = mainString;
// 处理滚动条
if (document.scrollingElement.scrollTop) {
document.scrollingElement.scrollTop = 0;
}
// 可能需要重新调用一下页面用到的功能
// other
runScript(scripts);
// 无刷新跳转
if (type === 'click') {
window.history.pushState({ href }, title, href);
} else {
oldUrl = href;
}
} else {
// 错误页面处理
oldMain.innerHTML = res.match(/<body>([\s\S]+?)<\/body>/i)?.[1]?.trim();
}
}).catch(e => {
// 错误页面处理
oldMain.innerHTML = `<pre>${e.toString()}</pre>`;
}).finally(() => {
closeLoading();
});
}
function runScript(list) {
let srcList = [];
let scriptList = [];
list.forEach(item => {
let src = item.match(/<script[^<>]+?src="([^\s<>"]+)"\s?([^<>]+)?>/)?.[1];
if (src) {
let oldScript = document.querySelector(`script[src*="${src}"]`);
if (!oldScript) {
srcList.push(src);
}
} else {
let script = item.match(/<script[^<>]*>([\s\S]+?)<\/script>/)?.[1];
scriptList.push(script);
}
});
let scriptBox = document.getElementById('scriptBox');
if (!scriptBox) {
scriptBox = document.createElement('div');
scriptBox.id = 'scriptBox';
document.body.appendChild(scriptBox);
} else {
scriptBox.innerHTML = '';
}
load();
function load() {
if (srcList.length === 0) {
runJs();
return;
}
let item = srcList.shift();
let script = document.createElement('script');
script.src = item;
document.head.appendChild(script);
script.addEventListener('load', () => {
load();
});
}
function runJs() {
if (scriptList.length === 0) {
return;
}
let item = scriptList.shift();
let script = document.createElement('script');
script.innerHTML = item;
scriptBox.appendChild(script);
runJs();
}
}
function loading() {
let loading = document.getElementById('loading');
if (loading) {
loading.style.display = 'flex';
} else {
loading = document.createElement('div');
loading.id = 'loading';
loading.style.display = 'flex';
loading.style.justifyContent = 'center';
loading.style.position = 'fixed';
loading.style.top = '0';
loading.style.left = '0';
loading.style.right = '0';
loading.style.bottom = '0';
loading.style.paddingTop = '3rem';
loading.style.zIndex = '999999999';
loading.innerHTML = '<div class="mdui-spinner mdui-spinner-colorful"></div>';
document.body.appendChild(loading);
mdui.mutation();
}
}
function closeLoading() {
let loading = document.getElementById('loading');
if (loading) {
loading.style.display = 'none';
}
}