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

Widget:GameSwitcher:修订间差异

来自OGAS数据中枢
弃权者留言 | 贡献
无编辑摘要
弃权者留言 | 贡献
无编辑摘要
第3行: 第3行:
不接受参数,直接在首页调用:<code><nowiki>{{#widget:GFHomepageSwitcher}}</nowiki></code>
不接受参数,直接在首页调用:<code><nowiki>{{#widget:GFHomepageSwitcher}}</nowiki></code>
</noinclude><includeonly><script>
</noinclude><includeonly><script>
(function () {
( function () {
   'use strict';
   'use strict';


第16行: 第16行:
     var canonical = document.querySelector( 'link[rel="canonical"]' );
     var canonical = document.querySelector( 'link[rel="canonical"]' );
     if ( canonical ) {
     if ( canonical ) {
       var match = canonical.href.match( /^(https?:\/\/[^\/]+(?:\/[^\/]+)*?)\/wiki\// );
       var m = canonical.href.match( /^(https?:\/\/[^\/]+(?:\/[^\/]+)*?)\/wiki\// );
       if ( match ) { return match[ 1 ] + '/api.php'; }
       if ( m ) { return m[ 1 ] + '/api.php'; }
     }
     }
     return window.location.origin + '/api.php';
     return window.location.origin + '/api.php';
第28行: 第28行:
       .then( function ( data ) {
       .then( function ( data ) {
         var pages = data.query.pages;
         var pages = data.query.pages;
         var page = pages[ Object.keys( pages )[ 0 ] ];
         var page = pages[ Object.keys( pages )[ 0 ] ];
         if ( page.imageinfo && page.imageinfo[ 0 ] ) {
         if ( page.imageinfo && page.imageinfo[ 0 ] ) {
           callback( page.imageinfo[ 0 ].url );
           callback( page.imageinfo[ 0 ].url );
第36行: 第36行:
   }
   }


   function applyFadeColors() {
   function applyFadeColor() {
     var style = getComputedStyle( document.documentElement );
     var style = getComputedStyle( document.documentElement );
     var bg = style.getPropertyValue( '--color-surface-0' ).trim()
     var bg = style.getPropertyValue( '--color-surface-0' ).trim()
第45行: 第45行:
       el.style.background = 'linear-gradient(to bottom, transparent 0%, ' + bg + ' 100%)';
       el.style.background = 'linear-gradient(to bottom, transparent 0%, ' + bg + ' 100%)';
     }
     }
  }
  /* 滑动指示器:根据当前active tab的位置和宽度移动 */
  function moveIndicator( tab ) {
    var indicator = document.getElementById( 'gf-tab-indicator' );
    var switcher = document.getElementById( 'gf-switcher' );
    if ( !indicator || !switcher ) { return; }
    var switcherRect = switcher.getBoundingClientRect();
    var tabRect = tab.getBoundingClientRect();
    indicator.style.width = tabRect.width + 'px';
    indicator.style.transform = 'translateX(' + ( tabRect.left - switcherRect.left ) + 'px)';
   }
   }


第50行: 第61行:
   var switching = false;
   var switching = false;


   function switchGame( game ) {
   function switchGame( game, tabEl ) {
     if ( game === currentGame || switching ) { return; }
     if ( game === currentGame || switching ) { return; }
     switching = true;
     switching = true;


     var slides = document.querySelectorAll( '#gf-homepage .gf-hero-slide' );
     var slides = document.querySelectorAll( '#gf-homepage .gf-hero-slide' );
     var panels = document.querySelectorAll( '#gf-homepage .gf-content-panel' );
     var panels = document.querySelectorAll( '#gf-homepage .gf-content-panel' );
     var tabs   = document.querySelectorAll( '#gf-homepage .gf-tab' );
     var tabs   = document.querySelectorAll( '#gf-homepage .gf-tab' );


     var outSlide = document.getElementById( 'hero-' + currentGame );
     var outSlide = document.getElementById( 'hero-' + currentGame );
     var inSlide  = document.getElementById( 'hero-' + game );
     var inSlide  = document.getElementById( 'hero-' + game );


    /* 先把新slide的fg重置为缩放状态,让Ken Burns重新触发 */
     if ( inSlide ) {
     if ( inSlide ) {
       inSlide.style.zIndex    = '1';
       var inFg = inSlide.querySelector( '.gf-hero-fg' );
      inSlide.style.opacity    = '0';
      if ( inFg ) {
      inSlide.style.transition = 'opacity 0.5s ease';
        inFg.style.transition = 'none';
       void inSlide.offsetWidth;
        inFg.style.transform = window.innerWidth > 1200
       inSlide.style.opacity    = '1';
          ? 'translateX(-50%) scale(1.06)'
          : 'scale(1.06)';
        void inFg.offsetWidth;
        inFg.style.transition = '';
       }
    }
 
    /* 交叉淡入淡出 */
    if ( inSlide ) {
       inSlide.style.zIndex = '1';
      inSlide.classList.add( 'active' );
     }
     }
     if ( outSlide ) {
     if ( outSlide ) {
       outSlide.style.zIndex     = '0';
       outSlide.style.zIndex = '0';
       outSlide.style.opacity    = '1';
       outSlide.classList.remove( 'active' );
      outSlide.style.transition = 'opacity 0.5s ease';
      void outSlide.offsetWidth;
      outSlide.style.opacity    = '0';
     }
     }


     panels.forEach( function ( p ) {
     /* tab状态 */
      p.classList.toggle( 'active', p.id === 'content-' + game );
    } );
 
     tabs.forEach( function ( t ) {
     tabs.forEach( function ( t ) {
       var on = t.getAttribute( 'data-game' ) === game;
       var on = t.getAttribute( 'data-game' ) === game;
       t.classList.toggle( 'active', on );
       t.classList.toggle( 'active', on );
       t.setAttribute( 'aria-selected', on ? 'true' : 'false' );
       t.setAttribute( 'aria-selected', on ? 'true' : 'false' );
    } );
    /* 滑动指示器 */
    if ( tabEl ) { moveIndicator( tabEl ); }
    /* 内容面板 */
    panels.forEach( function ( p ) {
      p.classList.toggle( 'active', p.id === 'content-' + game );
     } );
     } );


     setTimeout( function () {
     setTimeout( function () {
       slides.forEach( function ( s ) {
       slides.forEach( function ( s ) {
         s.style.zIndex     = '';
         s.style.zIndex = '';
        s.style.opacity    = s.id === 'hero-' + game ? '1' : '0';
        s.style.transition = '';
       } );
       } );
       currentGame = game;
       currentGame = game;
       switching   = false;
       switching = false;
     }, 520 );
     }, 720 );
   }
   }


第101行: 第123行:
     if ( !tabs.length ) { return; }
     if ( !tabs.length ) { return; }


     /* 同时注入 bg(模糊层)和 fg(清晰层)*/
     /* 注入背景图 */
     Object.keys( heroImages ).forEach( function ( game ) {
     Object.keys( heroImages ).forEach( function ( game ) {
       getWikiImageUrl( heroImages[ game ], function ( url ) {
       getWikiImageUrl( heroImages[ game ], function ( url ) {
第112行: 第134行:
     } );
     } );


     applyFadeColors();
     applyFadeColor();
 
    /* 初始化指示器位置 */
    var firstActive = document.querySelector( '#gf-homepage .gf-tab.active' );
    if ( firstActive ) {
      /* 等布局稳定后再计算 */
      setTimeout( function () { moveIndicator( firstActive ); }, 50 );
    }


     tabs.forEach( function ( tab ) {
     tabs.forEach( function ( tab ) {
       tab.addEventListener( 'click', function () {
       tab.addEventListener( 'click', function () {
         switchGame( this.getAttribute( 'data-game' ) );
         switchGame( this.getAttribute( 'data-game' ), this );
       } );
       } );
       tab.addEventListener( 'keydown', function ( e ) {
       tab.addEventListener( 'keydown', function ( e ) {
         if ( e.key === 'Enter' || e.key === ' ' ) {
         if ( e.key === 'Enter' || e.key === ' ' ) {
           e.preventDefault();
           e.preventDefault();
           switchGame( this.getAttribute( 'data-game' ) );
           switchGame( this.getAttribute( 'data-game' ), this );
         }
         }
       } );
       } );
    } );
    /* 窗口resize时重新定位指示器 */
    window.addEventListener( 'resize', function () {
      var active = document.querySelector( '#gf-homepage .gf-tab.active' );
      if ( active ) { moveIndicator( active ); }
     } );
     } );
   }
   }

2026年6月20日 (六) 22:14的版本

本Widget为少女前线系列多游戏首页提供切换交互逻辑。 不接受参数,直接在首页调用:{{#widget:GFHomepageSwitcher}}