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

Flutter带触发操作的左右滑动容器实现需求

实现两端触发操作的滑动组件方案

核心思路

监听滑动容器的scroll事件,计算滚动位置与容器、内容的尺寸关系,判断是否到达左右两端,触发对应操作的同时加入防重复触发机制,避免多次执行。

原生JS实现示例

HTML结构

<div class="scroll-container" id="scrollContainer">
  <div class="scroll-content">
    <div class="item">项1</div>
    <div class="item">项2</div>
    <div class="item">项3</div>
    <div class="item">项4</div>
    <div class="item">项5</div>
  </div>
</div>

CSS样式

.scroll-container {
  width: 100%;
  overflow-x: auto;
  white-space: nowrap;
  padding: 10px 0;
  -webkit-overflow-scrolling: touch; /* 优化移动端滚动流畅性 */
}
.scroll-content {
  display: inline-block;
}
.item {
  display: inline-block;
  width: 200px;
  height: 150px;
  margin: 0 10px;
  background: #f0f0f0;
  line-height: 150px;
  text-align: center;
}

JavaScript逻辑

const container = document.getElementById('scrollContainer');
let isProcessing = false; // 防重复触发锁
const tolerance = 5; // 容差,避免滚动精度问题

container.addEventListener('scroll', () => {
  const { scrollLeft, clientWidth, scrollWidth } = container;

  // 到达左端触发操作
  if (scrollLeft <= tolerance && !isProcessing) {
    isProcessing = true;
    console.log('执行左端操作');
    // 替换为你的业务逻辑,比如加载左侧内容
    setTimeout(() => {
      const newItem = document.createElement('div');
      newItem.className = 'item';
      newItem.textContent = `新左项${Date.now()}`;
      container.querySelector('.scroll-content').prepend(newItem);
      isProcessing = false;
    }, 1000);
  }

  // 到达右端触发操作
  if (scrollLeft + clientWidth >= scrollWidth - tolerance && !isProcessing) {
    isProcessing = true;
    console.log('执行右端操作');
    // 替换为你的业务逻辑,比如加载右侧内容
    setTimeout(() => {
      const newItem = document.createElement('div');
      newItem.className = 'item';
      newItem.textContent = `新右项${Date.now()}`;
      container.querySelector('.scroll-content').append(newItem);
      isProcessing = false;
    }, 1000);
  }
});

Vue 3版本实现示例

<template>
  <div class="scroll-container" @scroll="handleScroll">
    <div class="scroll-content">
      <div class="item" v-for="item in items" :key="item.id">
        {{ item.name }}
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue';

const items = ref(Array.from({ length: 5 }, (_, i) => ({ id: i, name: `项${i+1}` })));
const isProcessing = ref(false);
const tolerance = 5;

const handleScroll = (e) => {
  if (isProcessing.value) return;
  const { scrollLeft, clientWidth, scrollWidth } = e.target;

  // 左端触发
  if (scrollLeft <= tolerance) {
    isProcessing.value = true;
    console.log('触发左端操作');
    // 模拟异步加载
    setTimeout(() => {
      const newItems = Array.from({ length: 2 }, (_, i) => ({
        id: Date.now() + i,
        name: `新左项${i+1}`
      }));
      items.value = [...newItems, ...items.value];
      isProcessing.value = false;
    }, 1000);
  }

  // 右端触发
  if (scrollLeft + clientWidth >= scrollWidth - tolerance) {
    isProcessing.value = true;
    console.log('触发右端操作');
    // 模拟异步加载
    setTimeout(() => {
      const newItems = Array.from({ length: 2 }, (_, i) => ({
        id: Date.now() + i,
        name: `新右项${i+1}`
      }));
      items.value = [...items.value, ...newItems];
      isProcessing.value = false;
    }, 1000);
  }
};
</script>

<style scoped>
.scroll-container {
  width: 100%;
  overflow-x: auto;
  white-space: nowrap;
  padding: 10px 0;
  -webkit-overflow-scrolling: touch;
}
.scroll-content {
  display: inline-block;
}
.item {
  display: inline-block;
  width: 200px;
  height: 150px;
  margin: 0 10px;
  background: #f0f0f0;
  line-height: 150px;
  text-align: center;
}
</style>

关键注意事项

  • 防重复触发:用锁变量或节流函数控制操作执行频率,避免滚动时多次触发异步操作
  • 容差设置:不要用绝对相等判断滚动位置,设置5px左右的容差适配滚动精度问题
  • 异步处理:如果触发的是接口请求等异步操作,必须在操作完成后再解锁,防止并发请求
  • 移动端适配:添加-webkit-overflow-scrolling: touch;优化移动端滚动流畅度

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 01:17:43