一切皆为插件的开发者工具运行时框架
🧩 核心特性:
- 插件热插拔 (importlib 动态加载)
- 依赖自动解析 (拓扑排序 + 循环检测)
- 企业级稳定 (熔断/降级/重试/隔离)
- 事件驱动 (发布/订阅事件总线)
- 完整配置 (YAML 配置 + 热重载)
100 lines
3.4 KiB
JavaScript
100 lines
3.4 KiB
JavaScript
/**
|
|
* 极简软重定向 (SPA Router)
|
|
* 拦截所有站内链接,使用 fetch + DOM 替换实现无刷新跳转
|
|
*/
|
|
(function() {
|
|
document.addEventListener('click', function(e) {
|
|
const link = e.target.closest('a');
|
|
if (!link || link.target === '_blank' || link.href.startsWith('javascript:')) return;
|
|
|
|
const url = new URL(link.href);
|
|
if (url.origin !== window.location.origin) return; // 仅拦截站内
|
|
|
|
e.preventDefault();
|
|
navigate(url.pathname + url.search, true);
|
|
});
|
|
|
|
window.addEventListener('popstate', function(e) {
|
|
if (e.state && e.state.html) {
|
|
document.title = e.state.title;
|
|
document.querySelector('main').innerHTML = e.state.html;
|
|
initPage();
|
|
} else {
|
|
navigate(window.location.pathname + window.location.search, false);
|
|
}
|
|
});
|
|
|
|
async function navigate(url, push) {
|
|
try {
|
|
const res = await fetch(url);
|
|
if (!res.ok) { window.location.href = url; return; }
|
|
|
|
const html = await res.text();
|
|
const doc = new DOMParser().parseFromString(html, 'text/html');
|
|
|
|
// 1. 更新标题
|
|
document.title = doc.title;
|
|
|
|
// 2. 替换 Main 内容
|
|
const newMain = doc.querySelector('main');
|
|
const oldMain = document.querySelector('main');
|
|
if (newMain && oldMain) {
|
|
oldMain.innerHTML = newMain.innerHTML;
|
|
}
|
|
|
|
// 3. 更新 URL
|
|
if (push) {
|
|
history.pushState({
|
|
url: url,
|
|
html: newMain ? newMain.innerHTML : '',
|
|
title: doc.title
|
|
}, '', url);
|
|
window.scrollTo(0, 0);
|
|
}
|
|
|
|
// 4. 更新 Dock 高亮
|
|
document.querySelectorAll('#dock .dock-item').forEach(el => {
|
|
const href = el.getAttribute('href');
|
|
el.classList.toggle('active', href && url.startsWith(href));
|
|
});
|
|
|
|
// 5. 重新注入脚本/逻辑
|
|
injectScripts(doc);
|
|
initPage();
|
|
|
|
} catch (err) {
|
|
console.error(err);
|
|
window.location.href = url;
|
|
}
|
|
}
|
|
|
|
function injectScripts(doc) {
|
|
doc.scripts.forEach(oldScript => {
|
|
const newScript = document.createElement('script');
|
|
Array.from(oldScript.attributes).forEach(attr => newScript.setAttribute(attr.name, attr.value));
|
|
if (oldScript.src) {
|
|
newScript.src = oldScript.src;
|
|
document.body.appendChild(newScript);
|
|
} else {
|
|
newScript.textContent = oldScript.textContent;
|
|
document.body.appendChild(newScript);
|
|
}
|
|
});
|
|
}
|
|
|
|
// 通用页面初始化入口
|
|
function initPage() {
|
|
// 尝试调用社区模块初始化
|
|
if (typeof initCommunity === 'function') {
|
|
// 如果脚本已加载,直接调用
|
|
initCommunity();
|
|
} else {
|
|
// 否则动态加载
|
|
if (location.pathname.includes('/community/') || location.pathname.endsWith('/community/')) {
|
|
const s = document.createElement('script');
|
|
s.src = '/community/assets/js/community.js';
|
|
document.body.appendChild(s);
|
|
}
|
|
}
|
|
}
|
|
})(); |