@@ -743,18 +743,19 @@ function initDemoRotator(){
743743
744744window . addEventListener ( 'load' , ( ) => { try { initDemoRotator ( ) ; } catch ( e ) { } } ) ;
745745// 1. 初始化变量
746+ // 1. 获取元素
746747const track = document . getElementById ( 'track' ) ;
747748const originalCards = document . querySelectorAll ( '.carousel-card' ) ;
748749const prevBtn = document . getElementById ( 'prevBtn' ) ;
749750const nextBtn = document . getElementById ( 'nextBtn' ) ;
750- const gapPx = 15 ;
751+ const gapPx = 15 ; // 必须和 CSS 里的 gap 保持一致
751752
752- // 动态计算宽度百分比
753+ // 2. 动态获取当前是从 60% 还是 75% 渲染
753754function getCardWidthPercent ( ) {
754755 return window . innerWidth < 768 ? 75 : 60 ;
755756}
756757
757- // 2. 克隆卡片
758+ // 3. 克隆首尾 (Clone)
758759const firstClone = originalCards [ 0 ] . cloneNode ( true ) ;
759760const lastClone = originalCards [ originalCards . length - 1 ] . cloneNode ( true ) ;
760761track . appendChild ( firstClone ) ;
@@ -764,11 +765,30 @@ let allCards = document.querySelectorAll('.carousel-card');
764765let currentIndex = 1 ;
765766let isTransitioning = false ;
766767
767- // 3. 核心切换函数
768+ // 4. 核心:更新位置 (使用纯 CSS calc,稳如老狗)
769+ function updateTrack ( animate ) {
770+ if ( animate ) {
771+ track . style . transition = 'transform 0.4s cubic-bezier(0.25, 1, 0.5, 1)' ;
772+ } else {
773+ track . style . transition = 'none' ;
774+ }
775+
776+ const wPercent = getCardWidthPercent ( ) ;
777+
778+ // 公式解释:
779+ // 居中偏移量 = (100% - 卡片宽度%) / 2
780+ // 移动距离 = 居中偏移量 - (当前索引 * (卡片宽度% + 间距px))
781+ const centerOffset = ( 100 - wPercent ) / 2 ;
782+ const val = `calc(${ centerOffset } % - ${ currentIndex } * (${ wPercent } % + ${ gapPx } px))` ;
783+
784+ track . style . transform = `translateX(${ val } )` ;
785+ }
786+
787+ // 5. 切换逻辑
768788function switchSlide ( direction ) {
769789 if ( isTransitioning ) return ;
770790
771- // 边界保护
791+ // 防止快速点击越界
772792 if ( direction === 1 && currentIndex >= allCards . length - 1 ) return ;
773793 if ( direction === - 1 && currentIndex <= 0 ) return ;
774794
@@ -778,52 +798,41 @@ function switchSlide(direction) {
778798 updateActive ( ) ;
779799}
780800
781- // === 4 . 事件绑定 (暴力修复点击问题) ===
801+ // 6 . 事件绑定 (暴力绑定 click 和 touchend)
782802
783- // 绑定点击
784- nextBtn . addEventListener ( 'click' , ( e ) => {
785- e . preventDefault ( ) ;
786- switchSlide ( 1 ) ;
787- } ) ;
788- prevBtn . addEventListener ( 'click' , ( e ) => {
789- e . preventDefault ( ) ;
790- switchSlide ( - 1 ) ;
791- } ) ;
803+ // 电脑端点击
804+ nextBtn . addEventListener ( 'click' , ( e ) => { e . preventDefault ( ) ; switchSlide ( 1 ) ; } ) ;
805+ prevBtn . addEventListener ( 'click' , ( e ) => { e . preventDefault ( ) ; switchSlide ( - 1 ) ; } ) ;
792806
793- // 绑定触摸结束 (针对部分安卓机)
794- // 为了防止 Click 和 Touchend 触发两次,我们加个简单的锁
807+ // 手机端触摸 (加锁防止双重触发)
795808let touchLock = false ;
796- function handleTouchBtn ( e , dir ) {
797- e . preventDefault ( ) ; // 防止触发后面的 click
798- e . stopPropagation ( ) ; // 防止冒泡
809+ function handleTouch ( e , dir ) {
799810 if ( touchLock ) return ;
800-
811+ e . preventDefault ( ) ; e . stopPropagation ( ) ; // 阻止冒泡
801812 switchSlide ( dir ) ;
802-
803813 touchLock = true ;
804- setTimeout ( ( ) => { touchLock = false ; } , 300 ) ;
814+ setTimeout ( ( ) => touchLock = false , 300 ) ;
805815}
816+ nextBtn . addEventListener ( 'touchend' , ( e ) => handleTouch ( e , 1 ) ) ;
817+ prevBtn . addEventListener ( 'touchend' , ( e ) => handleTouch ( e , - 1 ) ) ;
806818
807- nextBtn . addEventListener ( 'touchend' , ( e ) => handleTouchBtn ( e , 1 ) ) ;
808- prevBtn . addEventListener ( 'touchend' , ( e ) => handleTouchBtn ( e , - 1 ) ) ;
809-
810-
811- // 5. 触摸滑动支持 (Swipe)
819+ // 7. 手机滑动支持 (Swipe)
812820let touchStartX = 0 ;
813821track . addEventListener ( 'touchstart' , e => { touchStartX = e . changedTouches [ 0 ] . screenX ; } , { passive : true } ) ;
814822track . addEventListener ( 'touchend' , e => {
815823 const touchEndX = e . changedTouches [ 0 ] . screenX ;
816- if ( touchEndX < touchStartX - 50 ) switchSlide ( 1 ) ;
817- if ( touchEndX > touchStartX + 50 ) switchSlide ( - 1 ) ;
824+ if ( touchEndX < touchStartX - 50 ) switchSlide ( 1 ) ; // 左滑 -> 下一张
825+ if ( touchEndX > touchStartX + 50 ) switchSlide ( - 1 ) ; // 右滑 -> 上一张
818826} , { passive : true } ) ;
819827
820-
821- // 6. 无缝循环处理
828+ // 8. 无缝循环 & 视频同步
822829track . addEventListener ( 'transitionend' , ( ) => {
823830 isTransitioning = false ;
824831 let targetIndex = - 1 ;
825832
833+ // 到了克隆的最后一张 -> 跳回真实第1张
826834 if ( currentIndex === allCards . length - 1 ) targetIndex = 1 ;
835+ // 到了克隆的第一张 -> 跳回真实最后一张
827836 else if ( currentIndex === 0 ) targetIndex = allCards . length - 2 ;
828837
829838 if ( targetIndex !== - 1 ) {
@@ -837,7 +846,7 @@ track.addEventListener('transitionend', () => {
837846 allCards . forEach ( c => c . classList . add ( 'no-transition' ) ) ;
838847
839848 currentIndex = targetIndex ;
840- updateTrack ( false ) ;
849+ updateTrack ( false ) ; // 重新定位
841850 updateActive ( ) ;
842851
843852 void track . offsetHeight ; // 强制重绘
@@ -848,26 +857,17 @@ track.addEventListener('transitionend', () => {
848857 }
849858} ) ;
850859
851- // 7. 更新视图逻辑
852- function updateTrack ( animate ) {
853- if ( animate ) track . style . transition = 'transform 0.4s ease-out' ;
854- else track . style . transition = 'none' ;
855-
856- const wPercent = getCardWidthPercent ( ) ;
857- const centerOffset = ( 100 - wPercent ) / 2 ;
858- const val = `calc(${ centerOffset } % - ${ currentIndex } * (${ wPercent } % + ${ gapPx } px))` ;
859- track . style . transform = `translateX(${ val } )` ;
860- }
861-
860+ // 9. 激活状态 (只播中间,两边暂停)
862861function updateActive ( ) {
863862 allCards . forEach ( ( card , index ) => {
864863 const v = card . querySelector ( 'video' ) ;
865864 if ( index === currentIndex ) {
866865 card . classList . add ( 'is-active' ) ;
867866 if ( v ) {
868- v . muted = true ;
869- v . playsInline = true ;
870- v . play ( ) . catch ( ( ) => { } ) ;
867+ v . muted = true ;
868+ v . playsInline = true ;
869+ // 必须加 catch 防止报错
870+ v . play ( ) . catch ( ( ) => { } ) ;
871871 }
872872 } else {
873873 card . classList . remove ( 'is-active' ) ;
@@ -879,4 +879,6 @@ function updateActive() {
879879// 初始化
880880updateTrack ( false ) ;
881881updateActive ( ) ;
882+
883+ // 监听窗口大小变化(自动适应横竖屏)
882884window . addEventListener ( 'resize' , ( ) => updateTrack ( false ) ) ;
0 commit comments