Widget:GameSwitcher:修订间差异
来自OGAS数据中枢
更多操作
无编辑摘要 |
无编辑摘要 |
||
| 第9行: | 第9行: | ||
var storageKey = 'gs-cache-'; | var storageKey = 'gs-cache-'; | ||
// ============ 初始化头图 ============ | // ============ 初始化双层头图 ============ | ||
var layerA = document.createElement('div'); | |||
var | var layerB = document.createElement('div'); | ||
if (heroWrap | layerA.className = 'gs-hero-layer'; | ||
heroWrap. | layerB.className = 'gs-hero-layer'; | ||
heroWrap. | layerB.style.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) { | if (firstBtn) { | ||
firstBtn.classList.add('gs-active'); | firstBtn.classList.add('gs-active'); | ||
firstBtn.setAttribute('aria-selected', 'true'); | firstBtn.setAttribute('aria-selected', 'true'); | ||
if (heroWrap) { | |||
activeLayer.style.backgroundImage = 'url(' + firstBtn.dataset.hero + ')'; | |||
} | |||
} | } | ||
// 默认面板直接可见,不走入场动画 | |||
var defaultPanel = switcher.querySelector('.gs-content-panel.gs-active'); | var defaultPanel = switcher.querySelector('.gs-content-panel.gs-active'); | ||
if (defaultPanel) { | if (defaultPanel) { | ||
defaultPanel.classList.add('gs-visible'); | defaultPanel.classList.add('gs-visible'); | ||
} | } | ||
| 第97行: | 第108行: | ||
} | } | ||
panel.classList.add('gs-active'); | panel.classList.add('gs-active'); | ||
setTimeout(function () { | setTimeout(function () { | ||
| 第106行: | 第116行: | ||
} | } | ||
// ============ 头图交叉溶解 ============ | // ============ 头图交叉溶解(双层互换) ============ | ||
function switchHero(url) { | function switchHero(url) { | ||
if (!heroWrap || !url) return; | if (!heroWrap || !url) return; | ||
if ( | if (activeLayer.style.backgroundImage === 'url("' + url + '")') return; | ||
var img = new Image(); | var img = new Image(); | ||
img.onload = function () { | img.onload = function () { | ||
// 把新图写入非活跃层,然后淡入 | |||
inactiveLayer.style.backgroundImage = 'url(' + url + ')'; | |||
inactiveLayer.style.opacity = '1'; | |||
activeLayer.style.opacity = '0'; | |||
// 互换两层的角色 | |||
var temp = activeLayer; | |||
activeLayer = inactiveLayer; | |||
inactiveLayer = temp; | |||
}; | }; | ||
img.src = url; | img.src = url; | ||
2026年6月20日 (六) 11:20的版本
<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 layerA = document.createElement('div');
var layerB = document.createElement('div');
layerA.className = 'gs-hero-layer';
layerB.className = 'gs-hero-layer';
layerB.style.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 + ')';
inactiveLayer.style.opacity = '1';
activeLayer.style.opacity = '0';
// 互换两层的角色
var temp = activeLayer;
activeLayer = inactiveLayer;
inactiveLayer = temp;
};
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>