微件:GameSwitcher
来自OGAS数据中枢
更多操作
<script type="text/javascript"> document.addEventListener('DOMContentLoaded', function () {
var switcher = document.querySelector('.game-switcher');
if (!switcher) return;
var heroWrap = document.getElementById('gs-hero-wrap');
var loaded = {};
var prefetching = {};
var storageKey = 'gs-cache-';
// ============ 初始化双层头图 ============ var layerStyle = 'position:absolute;top:0;left:0;width:100%;height:100%;background-size:cover;background-position:center;transition:opacity 0.4s ease';
var layerA = document.createElement('div');
var layerB = document.createElement('div');
layerA.className = 'gs-hero-layer';
layerB.className = 'gs-hero-layer';
layerA.style.cssText = layerStyle + ';opacity:1';
layerB.style.cssText = layerStyle + ';opacity:0';
if (heroWrap) {
heroWrap.appendChild(layerA);
heroWrap.appendChild(layerB);
}
var activeLayer = layerA; var inactiveLayer = layerB;
// ============ 初始化按钮和头图 ============
var firstBtn = switcher.querySelector('.gs-tab-btn');
if (firstBtn) {
firstBtn.classList.add('gs-active');
firstBtn.setAttribute('aria-selected', 'true');
if (heroWrap) {
activeLayer.style.backgroundImage = 'url(' + firstBtn.dataset.hero + ')';
}
}
// 默认面板直接可见,不走入场动画
var defaultPanel = switcher.querySelector('.gs-content-panel.gs-active');
if (defaultPanel) {
defaultPanel.classList.add('gs-visible');
}
// ============ 点击 ============
switcher.addEventListener('click', function (e) {
var btn = e.target.closest('.gs-tab-btn');
if (btn) activate(btn);
});
// ============ 键盘 ============
switcher.addEventListener('keydown', function (e) {
var btn = e.target.closest('.gs-tab-btn');
if (!btn) return;
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
activate(btn);
}
if (e.key === 'ArrowRight' || e.key === 'ArrowLeft') {
e.preventDefault();
var btns = Array.from(switcher.querySelectorAll('.gs-tab-btn'));
var idx = btns.indexOf(btn);
var next = e.key === 'ArrowRight' ? idx + 1 : idx - 1;
if (next >= 0 && next < btns.length) btns[next].focus();
}
});
// ============ 悬停预加载 ============
switcher.addEventListener('mouseenter', function (e) {
var btn = e.target.closest('.gs-tab-btn');
if (!btn) return;
var panelId = btn.dataset.panel;
var pageName = btn.dataset.page;
if (pageName && !loaded[panelId] && !prefetching[panelId]) {
prefetch(panelId, pageName);
}
}, true);
// ============ 激活面板 ============
function activate(btn) {
if (btn.classList.contains('gs-active')) return;
var panelId = btn.dataset.panel; var heroSrc = btn.dataset.hero; var pageName = btn.dataset.page;
switchHero(heroSrc);
// 按钮高亮
switcher.querySelectorAll('.gs-tab-btn').forEach(function (b) {
b.classList.remove('gs-active');
b.setAttribute('aria-selected', 'false');
});
btn.classList.add('gs-active');
btn.setAttribute('aria-selected', 'true');
// 隐藏当前面板
switcher.querySelectorAll('.gs-content-panel').forEach(function (p) {
p.classList.remove('gs-visible');
p.classList.remove('gs-active');
});
// 找到或创建目标面板
var panel = document.getElementById(panelId);
if (!panel) {
panel = document.createElement('div');
panel.id = panelId;
panel.className = 'gs-content-panel';
switcher.querySelector('.gs-content').appendChild(panel);
loadContent(panel, panelId, pageName);
}
panel.classList.add('gs-active');
setTimeout(function () {
panel.classList.add('gs-visible');
}, 16);
schedulePrefetchOthers(); }
// ============ 头图交叉溶解(双层互换) ============
function switchHero(url) {
if (!heroWrap || !url) return;
if (activeLayer.style.backgroundImage === 'url("' + url + '")') return;
var img = new Image();
img.onload = function () {
// 先把新图写入非活跃层
inactiveLayer.style.backgroundImage = 'url(' + url + ')';
// 隔两帧确保浏览器已完成一次渲染,再触发 transition
requestAnimationFrame(function () {
requestAnimationFrame(function () {
inactiveLayer.style.opacity = '1';
activeLayer.style.opacity = '0';
// transition 结束后再互换角色,防止快速点击时状态错乱
var _active = activeLayer;
var _inactive = inactiveLayer;
setTimeout(function () {
activeLayer = _inactive;
inactiveLayer = _active;
}, 420);
});
});
};
img.src = url;
}
// ============ 内容加载 ============
function loadContent(panel, panelId, pageName) {
if (loaded[panelId]) {
panel.innerHTML = loaded[panelId];
return;
}
try {
var stored = localStorage.getItem(storageKey + panelId);
if (stored) {
loaded[panelId] = stored;
panel.innerHTML = stored;
return;
}
} catch (e) {}
if (!pageName) return;
panel.innerHTML = '
加载中...
';
fetchPage(pageName).then(function (html) {
loaded[panelId] = html;
try { localStorage.setItem(storageKey + panelId, html); } catch (e) {}
panel.innerHTML = html;
}).catch(function () {
panel.innerHTML = '
加载失败,<a href="javascript:location.reload()">刷新</a>重试
';
}); }
// ============ 预加载 ============
function prefetch(panelId, pageName) {
prefetching[panelId] = true;
try {
var stored = localStorage.getItem(storageKey + panelId);
if (stored) {
loaded[panelId] = stored;
prefetching[panelId] = false;
return;
}
} catch (e) {}
fetchPage(pageName).then(function (html) {
loaded[panelId] = html;
try { localStorage.setItem(storageKey + panelId, html); } catch (e) {}
}).finally(function () {
prefetching[panelId] = false;
});
}
function schedulePrefetchOthers() {
setTimeout(function () {
switcher.querySelectorAll('.gs-tab-btn').forEach(function (btn) {
var panelId = btn.dataset.panel;
var pageName = btn.dataset.page;
if (!loaded[panelId] && !prefetching[panelId] && pageName) {
prefetch(panelId, pageName);
}
});
}, 500);
}
// ============ API 请求 ============
function fetchPage(pageName) {
var url = mw.util.wikiScript('api') +
'?action=parse&page=' + encodeURIComponent(pageName) +
'&prop=text&format=json&disablelimitreport=1&origin=*';
return fetch(url)
.then(function (r) { return r.json(); })
.then(function (data) {
if (data.parse && data.parse.text) return data.parse.text['*'];
throw new Error('empty');
});
}
}); </script>