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

Widget:GameSwitcher:修订间差异

来自OGAS数据中枢
弃权者留言 | 贡献
无编辑摘要
弃权者留言 | 贡献
无编辑摘要
第1行: 第1行:
<script>
<script type="text/javascript">
(function ($) {
document.addEventListener('DOMContentLoaded', function () {
$(function () {
   var switcher = document.querySelector('.game-switcher');
   var $switcher = $('.game-switcher');
   if (!switcher) return;
   if (!$switcher.length) return;


   var $hero = $('#gs-hero-wrap');
   var heroWrap = document.getElementById('gs-hero-wrap');
   var $heroImg = $hero.find('img');
   var heroImg = heroWrap ? heroWrap.querySelector('img') : null;
   var loaded = {};       // 内存缓存: { panelId: html }
   var loaded = {};
   var prefetching = {}; // 防重复预取
   var prefetching = {};
   var storageKey = 'gs-cache-';
   var storageKey = 'gs-cache-';


   // ============ 初始化 ============
   // ============ 初始化 ============
   var $firstBtn = $switcher.find('.gs-tab-btn').first();
   var firstBtn = switcher.querySelector('.gs-tab-btn');
   if ($firstBtn.length) {
   if (firstBtn) {
     $firstBtn.addClass('gs-active').attr('aria-selected', 'true');
     firstBtn.classList.add('gs-active');
     if ($heroImg.length && !$heroImg.attr('src')) {
    firstBtn.setAttribute('aria-selected', 'true');
       $heroImg.attr('src', $firstBtn.data('hero'));
     if (heroImg && !heroImg.getAttribute('src')) {
       heroImg.src = firstBtn.dataset.hero;
     }
     }
   }
   }
第22行: 第22行:


   // ============ 点击 ============
   // ============ 点击 ============
   $switcher.on('click', '.gs-tab-btn', function () {
   switcher.addEventListener('click', function (e) {
     activate($(this));
    var btn = e.target.closest('.gs-tab-btn');
     if (btn) activate(btn);
   });
   });


   // ============ 键盘 ============
   // ============ 键盘 ============
   $switcher.on('keydown', '.gs-tab-btn', function (e) {
   switcher.addEventListener('keydown', function (e) {
    var btn = e.target.closest('.gs-tab-btn');
    if (!btn) return;
     if (e.key === 'Enter' || e.key === ' ') {
     if (e.key === 'Enter' || e.key === ' ') {
       e.preventDefault();
       e.preventDefault();
       activate($(this));
       activate(btn);
     }
     }
     if (e.key === 'ArrowRight' || e.key === 'ArrowLeft') {
     if (e.key === 'ArrowRight' || e.key === 'ArrowLeft') {
       e.preventDefault();
       e.preventDefault();
       var $btns = $switcher.find('.gs-tab-btn');
       var btns = Array.from(switcher.querySelectorAll('.gs-tab-btn'));
       var idx = $btns.index(this);
       var idx = btns.indexOf(btn);
       var next = e.key === 'ArrowRight' ? idx + 1 : idx - 1;
       var next = e.key === 'ArrowRight' ? idx + 1 : idx - 1;
       if (next >= 0 && next < $btns.length) {
       if (next >= 0 && next < btns.length) btns[next].focus();
        $btns.eq(next).focus();
      }
     }
     }
   });
   });


   // ============ 悬停预加载 ============
   // ============ 悬停预加载 ============
   $switcher.on('mouseenter', '.gs-tab-btn', function () {
   switcher.addEventListener('mouseenter', function (e) {
     var panelId = $(this).data('panel');
    var btn = e.target.closest('.gs-tab-btn');
     var pageName = $(this).data('page');
    if (!btn) return;
     var panelId = btn.dataset.panel;
     var pageName = btn.dataset.page;
     if (pageName && !loaded[panelId] && !prefetching[panelId]) {
     if (pageName && !loaded[panelId] && !prefetching[panelId]) {
       prefetch(panelId, pageName);
       prefetch(panelId, pageName);
     }
     }
   });
   }, true);


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


   // ============ 激活面板 ============
   // ============ 激活面板 ============
   function activate($btn) {
   function activate(btn) {
     if ($btn.hasClass('gs-active')) return;
     if (btn.classList.contains('gs-active')) return;


     var panelId = $btn.data('panel');
     var panelId = btn.dataset.panel;
     var heroSrc = $btn.data('hero');
     var heroSrc = btn.dataset.hero;
     var pageName = $btn.data('page');
     var pageName = btn.dataset.page;


    // 1. 头图淡入淡出
     switchHero(heroSrc);
     switchHero(heroSrc);


     // 2. 按钮高亮
     switcher.querySelectorAll('.gs-tab-btn').forEach(function (b) {
    $switcher.find('.gs-tab-btn')
       b.classList.remove('gs-active');
       .removeClass('gs-active')
       b.setAttribute('aria-selected', 'false');
       .attr('aria-selected', 'false');
     });
     $btn.addClass('gs-active').attr('aria-selected', 'true');
    btn.classList.add('gs-active');
    btn.setAttribute('aria-selected', 'true');


     // 3. 面板切换
     switcher.querySelectorAll('.gs-content-panel').forEach(function (p) {
    var $panel = $('#' + panelId);
      p.classList.remove('gs-active');
    $switcher.find('.gs-content-panel').removeClass('gs-active');
    });


     if (!$panel.length) {
    var panel = document.getElementById(panelId);
       $panel = $('<div>', {
     if (!panel) {
        id: panelId,
       panel = document.createElement('div');
        class: 'gs-content-panel gs-active'
      panel.id = panelId;
       }).appendTo('.gs-content');
      panel.className = 'gs-content-panel gs-active';
       loadContent($panel, panelId, pageName);
       switcher.querySelector('.gs-content').appendChild(panel);
       loadContent(panel, panelId, pageName);
     } else {
     } else {
       $panel.addClass('gs-active');
       panel.classList.add('gs-active');
     }
     }


    // 4. URL hash
     setHash(panelId);
     setHash(panelId);
    // 5. 后台静默预取其余
     schedulePrefetchOthers();
     schedulePrefetchOthers();
   }
   }


   // ============ 头图切换(预加载 + 淡入淡出) ============
   // ============ 头图切换 ============
   function switchHero(url) {
   function switchHero(url) {
     if (!$hero.length || !url) return;
     if (!heroWrap || !heroImg || !url) return;
     var current = $heroImg.attr('src');
     if (heroImg.src === url) return;
    if (current === url) return;


     $('<img>').on('load', function () {
     var preload = new Image();
       $hero.addClass('gs-hero--fade');
    preload.onload = function () {
       heroWrap.classList.add('gs-hero--fade');
       setTimeout(function () {
       setTimeout(function () {
         $heroImg.attr('src', url);
         heroImg.src = url;
         $hero.removeClass('gs-hero--fade');
         heroWrap.classList.remove('gs-hero--fade');
       }, 160);
       }, 160);
     }).attr('src', url);
     };
    preload.src = url;
   }
   }


   // ============ 内容加载 ============
   // ============ 内容加载 ============
   function loadContent($panel, panelId, pageName) {
   function loadContent(panel, panelId, pageName) {
     if (loaded[panelId]) {
     if (loaded[panelId]) { panel.innerHTML = loaded[panelId]; return; }
      $panel.html(loaded[panelId]);
      return;
    }


     var stored = mw.storage.get(storageKey + panelId);
     try {
    if (stored) {
      var stored = localStorage.getItem(storageKey + panelId);
      loaded[panelId] = stored;
      if (stored) { loaded[panelId] = stored; panel.innerHTML = stored; return; }
      $panel.html(stored);
     } catch (e) {}
      return;
     }


     if (!pageName) return;
     if (!pageName) return;
    panel.innerHTML = '<div class="gs-loading">加载中...</div>';


     $panel.html('<div class="gs-loading">加载中...</div>');
     fetchPage(pageName).then(function (html) {
 
       loaded[panelId] = html;
    $.get(mw.util.wikiScript('api'), {
      try { localStorage.setItem(storageKey + panelId, html); } catch (e) {}
      action: 'parse',
      panel.innerHTML = html;
      page: pageName,
     }).catch(function () {
      prop: 'text',
       panel.innerHTML = '<div class="gs-loading">加载失败,<a href="javascript:location.reload()">刷新</a>重试</div>';
      format: 'json',
      disablelimitreport: 1
    }).then(function (data) {
       if (data.parse && data.parse.text) {
        var html = data.parse.text['*'];
        loaded[panelId] = html;
        try { mw.storage.set(storageKey + panelId, html); } catch (e) {}
        $panel.html(html);
      }
     }).fail(function () {
       $panel.html('<div class="gs-loading">加载失败,<a href="javascript:location.reload()">刷新</a>重试</div>');
     });
     });
   }
   }
第147行: 第134行:
   function prefetch(panelId, pageName) {
   function prefetch(panelId, pageName) {
     prefetching[panelId] = true;
     prefetching[panelId] = true;
    try {
      var stored = localStorage.getItem(storageKey + panelId);
      if (stored) { loaded[panelId] = stored; prefetching[panelId] = false; return; }
    } catch (e) {}


     var stored = mw.storage.get(storageKey + panelId);
     fetchPage(pageName).then(function (html) {
    if (stored) {
       loaded[panelId] = html;
      loaded[panelId] = stored;
      try { localStorage.setItem(storageKey + panelId, html); } catch (e) {}
      prefetching[panelId] = false;
     }).finally(function () {
      return;
    }
 
    $.get(mw.util.wikiScript('api'), {
      action: 'parse',
      page: pageName,
      prop: 'text',
      format: 'json',
      disablelimitreport: 1
    }).then(function (data) {
       if (data.parse && data.parse.text) {
        var html = data.parse.text['*'];
        loaded[panelId] = html;
        try { mw.storage.set(storageKey + panelId, html); } catch (e) {}
      }
     }).always(function () {
       prefetching[panelId] = false;
       prefetching[panelId] = false;
     });
     });
第174行: 第149行:
   function schedulePrefetchOthers() {
   function schedulePrefetchOthers() {
     setTimeout(function () {
     setTimeout(function () {
       $switcher.find('.gs-tab-btn').each(function () {
       switcher.querySelectorAll('.gs-tab-btn').forEach(function (btn) {
         var panelId = $(this).data('panel');
         var panelId = btn.dataset.panel;
         var pageName = $(this).data('page');
         var pageName = btn.dataset.page;
         if (!loaded[panelId] && !prefetching[panelId] && pageName) {
         if (!loaded[panelId] && !prefetching[panelId] && pageName) {
           prefetch(panelId, pageName);
           prefetch(panelId, pageName);
第182行: 第157行:
       });
       });
     }, 500);
     }, 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');
      });
   }
   }


第190行: 第178行:


   function restoreHash() {
   function restoreHash() {
     var hash = window.location.hash.replace('#', '');
     var hash = location.hash.replace('#', '');
     if (hash && hash.indexOf('panel-') === 0) {
     if (hash && hash.indexOf('panel-') === 0) {
       var $btn = $switcher.find('[data-panel="' + hash + '"]');
       var btn = switcher.querySelector('[data-panel="' + hash + '"]');
       if ($btn.length && !$btn.hasClass('gs-active')) {
       if (btn && !btn.classList.contains('gs-active')) activate(btn);
        activate($btn);
      }
     }
     }
   }
   }
});
});
}(jQuery));
</script>
</script>

2026年6月20日 (六) 10:52的版本

<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;
   }
 }
 restoreHash();
 // ============ 点击 ============
 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);
 // ============ URL hash ============
 window.addEventListener('hashchange', restoreHash);
 // ============ 激活面板 ============
 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');
   }
   setHash(panelId);
   schedulePrefetchOthers();
 }
 // ============ 头图切换 ============
 function switchHero(url) {
   if (!heroWrap || !heroImg || !url) return;
   if (heroImg.src === url) return;
   var preload = new Image();
   preload.onload = function () {
     heroWrap.classList.add('gs-hero--fade');
     setTimeout(function () {
       heroImg.src = url;
       heroWrap.classList.remove('gs-hero--fade');
     }, 160);
   };
   preload.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');
     });
 }
 // ============ 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>