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

如何实现向下滚动时,含分类的ListView随分类位置横向移动?

实现滚动页面时分类栏横向联动的方案

核心思路

  • 监听页面滚动事件,实时检测当前可视区域内的分类内容区块
  • 匹配对应分类栏中的选项,计算横向滚动的目标位置,控制分类栏自动滚动对齐

原生JavaScript实现步骤及代码

  1. 准备DOM结构
<!-- 横向分类栏 -->
<div class="category-list-container">
  <ul class="category-list">
    <li class="category-item active" data-target="category-1">分类1</li>
    <li class="category-item" data-target="category-2">分类2</li>
    <li class="category-item" data-target="category-3">分类3</li>
    <li class="category-item" data-target="category-4">分类4</li>
    <li class="category-item" data-target="category-5">分类5</li>
  </ul>
</div>

<!-- 页面内容区块 -->
<div class="content-container">
  <div class="category-block" id="category-1">分类1内容</div>
  <div class="category-block" id="category-2">分类2内容</div>
  <div class="category-block" id="category-3">分类3内容</div>
  <div class="category-block" id="category-4">分类4内容</div>
  <div class="category-block" id="category-5">分类5内容</div>
</div>
  1. 基础样式
.category-list-container {
  position: sticky;
  top: 0;
  overflow-x: auto;
  background: #fff;
  border-bottom: 1px solid #eee;
}
.category-list {
  display: flex;
  list-style: none;
  padding: 0;
  margin: 0;
}
.category-item {
  padding: 12px 20px;
  cursor: pointer;
  white-space: nowrap;
}
.category-item.active {
  color: #1677ff;
  border-bottom: 2px solid #1677ff;
}
.category-block {
  height: 600px;
  margin: 20px 0;
  padding: 20px;
  border: 1px solid #eee;
}
  1. JavaScript逻辑
// 获取DOM元素
const categoryItems = document.querySelectorAll('.category-item');
const categoryBlocks = document.querySelectorAll('.category-block');
const categoryList = document.querySelector('.category-list');

// 存储每个分类区块的顶部位置和对应分类项的偏移
const categoryMap = Array.from(categoryBlocks).map(block => {
  const targetId = block.id;
  const item = document.querySelector(`.category-item[data-target="${targetId}"]`);
  return {
    blockTop: block.offsetTop,
    blockHeight: block.offsetHeight,
    itemLeft: item.offsetLeft,
    item: item
  };
});

// 监听滚动事件
window.addEventListener('scroll', () => {
  const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
  // 找到当前处于视口内的分类区块
  const currentCategory = categoryMap.find(item => {
    return scrollTop >= item.blockTop - 100 && scrollTop < item.blockTop + item.blockHeight - 100;
  });

  if (currentCategory) {
    // 移除所有激活状态
    categoryItems.forEach(item => item.classList.remove('active'));
    // 添加当前分类激活状态
    currentCategory.item.classList.add('active');
    // 计算横向滚动目标位置,让当前分类项居中(可选,也可以对齐左侧)
    const targetScrollLeft = currentCategory.itemLeft - (categoryList.offsetWidth - currentCategory.item.offsetWidth) / 2;
    // 平滑滚动
    categoryList.scrollTo({
      left: targetScrollLeft,
      behavior: 'smooth'
    });
  }
});

Vue3框架下的实现思路

  1. 使用onScroll监听页面滚动,通过ref获取分类栏和内容区块的DOM元素
  2. 计算每个内容区块的位置,滚动时匹配对应分类项,控制分类栏滚动并添加激活状态
<template>
  <div>
    <div class="category-list-container">
      <ul ref="categoryList" class="category-list">
        <li 
          v-for="category in categories" 
          :key="category.id"
          :class="{ active: activeCategoryId === category.id }"
          :data-target="`category-${category.id}`"
        >
          {{ category.name }}
        </li>
      </ul>
    </div>
    <div class="content-container">
      <div 
        v-for="category in categories" 
        :key="category.id"
        :id="`category-${category.id}`"
        class="category-block"
      >
        {{ category.name }}内容
      </div>
    </div>
  </div>
</template>

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

const categories = ref([
  { id: 1, name: '分类1' },
  { id: 2, name: '分类2' },
  { id: 3, name: '分类3' },
  { id: 4, name: '分类4' },
  { id: 5, name: '分类5' }
]);
const categoryList = ref(null);
const activeCategoryId = ref(1);
let categoryMap = [];

const handleScroll = () => {
  const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
  const currentCategory = categoryMap.find(item => {
    return scrollTop >= item.blockTop - 100 && scrollTop < item.blockTop + item.blockHeight - 100;
  });
  if (currentCategory && activeCategoryId.value !== currentCategory.id) {
    activeCategoryId.value = currentCategory.id;
    const item = categoryList.value.querySelector(`[data-target="category-${currentCategory.id}"]`);
    const targetScrollLeft = item.offsetLeft - (categoryList.value.offsetWidth - item.offsetWidth) / 2;
    categoryList.value.scrollTo({
      left: targetScrollLeft,
      behavior: 'smooth'
    });
  }
};

onMounted(() => {
  categoryMap = categories.value.map(category => {
    const block = document.getElementById(`category-${category.id}`);
    const item = categoryList.value.querySelector(`[data-target="category-${category.id}"]`);
    return {
      id: category.id,
      blockTop: block.offsetTop,
      blockHeight: block.offsetHeight,
      itemLeft: item.offsetLeft
    };
  });
  window.addEventListener('scroll', handleScroll);
});

onUnmounted(() => {
  window.removeEventListener('scroll', handleScroll);
});
</script>

<style scoped>
/* 样式同原生示例,略 */
</style>

注意事项

  • 可调整滚动判断的阈值(示例中的100),让联动触发时机更贴合需求
  • 若内容为动态加载,需在内容渲染完成后重新计算分类区块的位置信息
  • 平滑滚动的behavior: 'smooth'在旧浏览器不兼容时,可自定义动画或使用轻量滚动库替代

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 20:12:14