You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为JavaScript双面板模态框添加左右滑动切换类功能?

为双面板模态框添加触控滑动切换功能

我有一个包含两个面板的模态框,其中一个默认处于画布外,点击链接可触发切换显示。目前已实现点击切换功能,但希望在触控设备上通过左右滑动来切换容器的类。曾尝试使用CSS的scroll-snap方案,但过渡效果不如现有实现流畅,且无法更新容器类。在示例中,点击“Trigger Cart”链接可唤起模态框,通过红色竖条(Pair With...)可切换两种状态,请问如何为其添加滑动切换功能?


实现方案

我们可以通过监听原生触控事件来追踪滑动行为,判断滑动方向和距离后触发类名切换,完全沿用现有流畅的CSS过渡效果:

  1. 记录滑动起始的X坐标
  2. 滑动过程中阻止页面滚动干扰
  3. 滑动结束时根据偏移量判断是否触发切换,最小滑动阈值设为50px(可按需调整)

完整代码

HTML(无需修改)
<div class="page">
  <a href="" class="trigger-cart">Trigger Cart</a>
</div>

<div class="cart">
  
  <div class="cart__main">
    
    <div class="cart-head">
      <h2>Header</h2>
<!--       <a href="btn-close">x</a> -->
    </div>
    
    <div class="cart-items">
      <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
      <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
    </div>
    
    <div class="cart-foot">
      <h2>Footer</h2>
    </div>
    
  </div>
  
  <div class="cart__toggle" id="toggle">
    <h4 class="cart__toggle-label">Pair with..</h4>
  </div>
  
  <div class="cart__upsell">
    
    <div class="cart-header">
      <h2>Pair With...</h2>
      <a href="btn-close">x</a>
    </div>
    
  </div>
  
  <div class="cart__pag">
    <div class="cart__pag-item"></div>
    <div class="cart__pag-item"></div>
  </div>
  
</div>
CSS(无需修改)
html,
body {
  min-height: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
}

.page {
  min-height: 100%;
}

.cart {
  background: white;
  display: flex;
  flex-direction: row;
  height: 100%;
  overflow: hidden;
  position: fixed;
  top: 0;
  right: -375px;
  transition: right .24s ease-out;
  width: 375px;
}

.cart-visible .cart {
  right: 0;
  animation: example 1.28s ease;
}

.cart-head {
  background: rgba(255, 0, 0, .24);
}

.cart-items {
  background: rgba(255, 0, 0, .24);
  flex: 1 1 auto;
  overflow: auto;
}

.cart-foot {
  background: rgba(255, 0, 0, .24);
  margin-top: auto;
  margin-bottom: 40px;
  width: 100%;
}

.cart__main,
.cart__toggle,
.cart__upsell {
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
}

.cart__main,
.cart__upsell {
  width: calc(100% - 48px);
}

.cart__main {
  margin: 0;
  transition: margin .24s ease-out;
}

.cart.cart-toggled .cart__main {
  margin-left: calc(-100% + 48px);
}

.cart.cart-toggled .cart__pag {
  margin-left: 48px;
}

.cart.cart-toggled .cart__pag-item:first-child {
  background: none;
}

.cart.cart-toggled .cart__pag-item:last-child {
  background: black;
}

.cart__toggle {
  background: red;
  height: 100%;
  padding: 16px 0;
  width: 48px;
}

.cart__toggle-label {
  transform: rotate(90deg);
  white-space: nowrap;
}


.cart__pag {
  display: flex;
  justify-content: center;
  position: absolute;
  bottom: 16px;
  left: 0;
  transition: margin .24s ease-out;
  width: calc(100% - 64px);
}

.cart__pag-item {
  border: 1px solid black;
  box-sizing: border-box;
  border-radius: 100%;
  height: 8px;
  margin: 0 2px;
  width: 8px;
}

.cart__pag-item:first-child {
  background: black;
}

@keyframes example {
  0%        {right: -375px;}
  40%       {right: 96px;}
  100%      {right: 0;}
}
JavaScript(新增滑动逻辑)
const html = document.querySelector('html');
const btnOpen = document.querySelector('.trigger-cart');
const allCloseButtons = document.querySelectorAll('.cart-head__close');

btnOpen.addEventListener('click', e => {
  e.preventDefault();
  html.classList.add('cart-visible');
});

allCloseButtons.forEach(el => {
  el.addEventListener('click', e => {
    e.preventDefault();
    html.classList.remove('cart-visible');

    setTimeout(function() {
        cart.classList.remove('cart-toggled');
    }, 320); // 与关闭菜单的动画时长匹配
  });
});


/* 点击切换逻辑 */
const cart = document.querySelector('.cart');
const toggle = document.querySelector('.cart__toggle');

const handleToggleClick = e => {
  e.preventDefault();
  cart.classList.toggle('cart-toggled');
};

const handleResize = () => {
  if (window.matchMedia(`(min-width: 64em)`).matches) {
    cart.classList.remove('cart-toggled');
  }
};

toggle.addEventListener('click', handleToggleClick);
window.addEventListener('resize', handleResize);

/* 新增滑动切换逻辑 */
let touchStartX = 0;
const SWIPE_THRESHOLD = 50; // 触发切换的最小滑动距离

cart.addEventListener('touchstart', (e) => {
  touchStartX = e.touches[0].clientX;
});

cart.addEventListener('touchmove', (e) => {
  // 阻止页面随滑动滚动
  e.preventDefault();
});

cart.addEventListener('touchend', (e) => {
  const touchEndX = e.changedTouches[0].clientX;
  const swipeDistance = touchEndX - touchStartX;

  // 根据滑动方向切换类
  if (Math.abs(swipeDistance) > SWIPE_THRESHOLD) {
    if (swipeDistance > 0) {
      // 向右滑动,切回主面板
      cart.classList.remove('cart-toggled');
    } else {
      // 向左滑动,切换到关联推荐面板
      cart.classList.add('cart-toggled');
    }
  }
});

内容的提问来源于stack exchange,提问作者user1406440

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 21:40:28