打开/关闭菜单
26
6679
46
1.2万
OGAS数据中枢
打开/关闭外观设置菜单
打开/关闭个人菜单
未登录
未登录用户的IP地址会在进行任意编辑后公开展示。

Widget:GameSwitcher:修订间差异

来自OGAS数据中枢
弃权者留言 | 贡献
无编辑摘要
弃权者留言 | 贡献
无编辑摘要
第19行: 第19行:
     }
     }
   }
   }
  restoreHash();


   // ============ 点击 ============
   // ============ 点击 ============
第55行: 第54行:
   }, true);
   }, true);


  // ============ URL hash ============
  window.addEventListener('hashchange', restoreHash);


   // ============ 激活面板 ============
   // ============ 激活面板 ============
第90行: 第87行:
     }
     }


    setHash(panelId);
     schedulePrefetchOthers();
     schedulePrefetchOthers();
   }
   }
第173行: 第169行:
   }
   }


  // ============ URL hash ============
  function setHash(panelId) {
    try { history.replaceState(null, '', '#' + panelId); } catch (e) {}
  }
  function restoreHash() {
    var hash = location.hash.replace('#', '');
    if (hash && hash.indexOf('panel-') === 0) {
      var btn = switcher.querySelector('[data-panel="' + hash + '"]');
      if (btn && !btn.classList.contains('gs-active')) activate(btn);
    }
  }
});
</script>
</script>

2026年6月20日 (六) 11:04的版本

<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 heroImg = heroWrap ? heroWrap.querySelector('img') : null;
 var loaded = {};
 var prefetching = {};
 var storageKey = 'gs-cache-';
 // ============ 初始化 ============
 var firstBtn = switcher.querySelector('.gs-tab-btn');
 if (firstBtn) {
   firstBtn.classList.add('gs-active');
   firstBtn.setAttribute('aria-selected', 'true');
   if (heroImg && !heroImg.getAttribute('src')) {
     heroImg.src = firstBtn.dataset.hero;
   }
 }
 // ============ 点击 ============
 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-active');
   });
   var panel = document.getElementById(panelId);
   if (!panel) {
     panel = document.createElement('div');
     panel.id = panelId;
     panel.className = 'gs-content-panel gs-active';
     switcher.querySelector('.gs-content').appendChild(panel);
     loadContent(panel, panelId, pageName);
   } else {
     panel.classList.add('gs-active');
   }
   schedulePrefetchOthers();
 }
 // ============ 头图切换 ============

function switchHero(url) {

 if (!heroWrap || !heroImg || !url) return;
 if (heroImg.src === url) return;
 var next = new Image();
 next.onload = function () {
   heroWrap.style.opacity = '0';
   setTimeout(function () {
     heroImg.src = url;
     heroWrap.style.opacity = '1';
   }, 300);
 };
 next.onerror = function () {};
 next.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>