将水平滚动指示器添加到 DIV

Posted

技术标签:

【中文标题】将水平滚动指示器添加到 DIV【英文标题】:Add horizontal scroll indicator to DIV 【发布时间】:2021-04-23 03:57:52 【问题描述】:

我想为可滚动的 DIV 容器显示一个水平滚动指示器。

经过一些测试,我很确定纯 CSS 不可能。 我在answer for a similar question 中找到了一个 sn-p。 不幸的是,我不知道如何根据需要更改脚本。

我正在使用一个简单的 DIV 容器,其中包含一些元素。 这是我的代码:

<div class="container">
    <div class="scroll-wrapper">
        <div class="scroll-container">
            <ul class="list-inline text-white text-center">
            
                <li class="list-inline-item" style="width: 200px;">
                    <div class="py-5 bg-dark"><h1 class="py-5">1</h1></div>
                </li>
                <li class="list-inline-item" style="width: 400px;">
                    <div class="py-5 bg-dark"><h1 class="py-5">2</h1></div>
                </li>
                [....]
            
            </ul>
        </div>
    </div>
    
    <div class="scroll-indicator">
        <div class="scroll-indicator-bar"></div>
    </div>
    
    <div class="d-flex justify-content-between">
        <button>Prev</button>
        <button>Next</button>
    </div>
</div>

还有 CSS:

.scroll-wrapper 
    width: 100%;
    overflow-x: scroll;
    overflow-y: hidden;
    position: relative;
    white-space: nowrap;


.scroll-indicator height: 4px; width: 100%; background-color: #ddd; margin-bottom: 2rem;

.scroll-indicator-bar height: 4px; width: 20%; background-color: #000;

Working example

有没有办法使用 CSS 和/或 jQuery 为滚动条指示器设置动画?

编辑:我在这里找到了另一个很好的例子:https://codepen.io/mahish/pen/RajmQw

我尝试使用示例中的代码,但上一个/下一个按钮不起作用。而且我也不知道如何使用滚动位置来显示和移动滚动指示器。

这是示例中的 JS 代码(更改为我的类名):

// duration of scroll animation
var scrollDuration = 300;
// paddles
var leftPaddle = document.getElementsByClassName('left-paddle');
var rightPaddle = document.getElementsByClassName('right-paddle');
// get items dimensions
var itemsLength = $('.item').length;
var itemSize = $('.item').outerWidth(true);
// get some relevant size for the paddle triggering point
var paddleMargin = 20;

// get wrapper width
var getMenuWrapperSize = function() 
    return $('.scroll-wrapper').outerWidth();

var menuWrapperSize = getMenuWrapperSize();
// the wrapper is responsive
$(window).on('resize', function() 
    menuWrapperSize = getMenuWrapperSize();
);
// size of the visible part of the menu is equal as the wrapper size 
var menuVisibleSize = menuWrapperSize;

// get total width of all menu items
var getMenuSize = function() 
    return itemsLength * itemSize;
;
var menuSize = getMenuSize();
// get how much of menu is invisible
var menuInvisibleSize = menuSize - menuWrapperSize;

// get how much have we scrolled to the left
var getMenuPosition = function() 
    return $('.scroll-container').scrollLeft();
;

// finally, what happens when we are actually scrolling the menu
$('.scroll-container').on('scroll', function() 

    // get how much of menu is invisible
    menuInvisibleSize = menuSize - menuWrapperSize;
    // get how much have we scrolled so far
    var menuPosition = getMenuPosition();

    var menuEndOffset = menuInvisibleSize - paddleMargin;

    // show & hide the paddles 
    // depending on scroll position
    if (menuPosition <= paddleMargin) 
        $(leftPaddle).addClass('hidden');
        $(rightPaddle).removeClass('hidden');
     else if (menuPosition < menuEndOffset) 
        // show both paddles in the middle
        $(leftPaddle).removeClass('hidden');
        $(rightPaddle).removeClass('hidden');
     else if (menuPosition >= menuEndOffset) 
        $(leftPaddle).removeClass('hidden');
        $(rightPaddle).addClass('hidden');


    // print important values
    $('#print-wrapper-size span').text(menuWrapperSize);
    $('#print-menu-size span').text(menuSize);
    $('#print-menu-invisible-size span').text(menuInvisibleSize);
    $('#print-menu-position span').text(menuPosition);

);

// scroll to left
$(rightPaddle).on('click', function() 
    $('.scroll-container').animate(  scrollLeft: menuInvisibleSize, scrollDuration);
);

// scroll to right
$(leftPaddle).on('click', function() 
    $('.scroll-container').animate(  scrollLeft: '0' , scrollDuration);
);

【问题讨论】:

【参考方案1】:

您可以使用 vanilla js 拥有自己的自定义水平滚动行为,您只需要处理 mousedownmouseupmousemove 事件,计算所需的滚动值并使用 transform: translateX() 样式移动元素,以及跟踪这些值,

我做了一些修改并添加了一些js代码,查看下面的sn-p:

const scrollBar = document.getElementById('myBar');
const scrollBarWrapper = document.getElementById('barWrapper');
const scrollContent = document.getElementById('scroll-container');

scrollBar.style.width =  ((scrollContent.offsetWidth * scrollBarWrapper.offsetWidth) / scrollContent.scrollWidth) + 'px';

let isScrolling = false;
let cursorX = 0;
let translateXValue = 0;

scrollBar.addEventListener('mousedown', function(e) 
    e.preventDefault();
    isScrolling = true;
    cursorX = e.clientX;
);

document.addEventListener('mouseup', function(e) 
    if (isScrolling) 
        e.preventDefault();
        isScrolling = false;
        translateXValue += (e.clientX - cursorX);
    
);

document.addEventListener('mousemove', function(e) 
    if (isScrolling && cursorX !== e.clientX) 
        e.preventDefault();
        const translateAmount = (translateXValue + (e.clientX - cursorX));
        const scrollLength = (barWrapper.offsetWidth - scrollBar.offsetWidth);
        const barScroll = Math.min(Math.max(0, translateAmount), scrollLength);
        const contentTranslateRatio = (barScroll * scrollContent.scrollWidth) / scrollContent.offsetWidth;
        
        scrollBar.style.transform = 'translateX(' + barScroll + 'px)';
        scrollContent.style.transform = 'translateX(' + -contentTranslateRatio + 'px)';
    
);
.scroll-wrapper 
    width: 100%;
    overflow: hidden;
    position: relative;
    white-space: nowrap;


.scroll-indicator height: 6px; width: 100%; background-color: #ddd; margin-bottom: 2rem;

.scroll-indicator-bar height: 6px; width: 20%; background-color: #000;
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet"/>
<div class="container" id="container">
    <div class="scroll-wrapper">
        <div class="scroll-container" id="scroll-container">
            <ul class="list-inline text-white text-center">
            
                <li class="list-inline-item" style="width: 200px;">
                    <div class="py-5 bg-dark"><h1 class="py-5">1</h1></div>
                </li>
                <li class="list-inline-item" style="width: 400px;">
                    <div class="py-5 bg-dark"><h1 class="py-5">2</h1></div>
                </li>
                <li class="list-inline-item" style="width: 300px;">
                    <div class="py-5 bg-dark"><h1 class="py-5">3</h1></div>
                </li>
                <li class="list-inline-item" style="width: 150px;">
                    <div class="py-5 bg-dark"><h1 class="py-5">4</h1></div>
                </li>
                <li class="list-inline-item" style="width: 250px;">
                    <div class="py-5 bg-dark"><h1 class="py-5">5</h1></div>
                </li>
                <li class="list-inline-item" style="width: 300px;">
                    <div class="py-5 bg-dark"><h1 class="py-5">6</h1></div>
                </li>
                <li class="list-inline-item" style="width: 200px;">
                    <div class="py-5 bg-dark"><h1 class="py-5">7</h1></div>
                </li>
                <li class="list-inline-item" style="width: 400px;">
                    <div class="py-5 bg-dark"><h1 class="py-5">8</h1></div>
                </li>
                <li class="list-inline-item" style="width: 300px;">
                    <div class="py-5 bg-dark"><h1 class="py-5">9</h1></div>
                </li>
            
            </ul>
        </div>
    </div>
    
    <div class="scroll-indicator" id="barWrapper">
        <div class="scroll-indicator-bar"  id="myBar"></div>
    </div>
    
    <div class="d-flex justify-content-between">
        <button>Prev</button>
        <button>Next</button>
    </div>
</div>

通过此代码,您可以根据内容动态滚动条宽度动态宽度,并且您可以管理自己的滚动行为,

然后,您可以添加自定义的 next() 和 previous() 函数来为滚动条和内容添加翻译,就像在 mousemove 处理程序中实现的那样

【讨论】:

谢谢!我会查一下。是否可以选择在单个页面上使用多个实例? 不幸的是代码不起作用:codepen.io/cray_code/pen/yLaZdMP 它工作正常,请尝试使用滚动条本身,(拖动它),您仍然需要添加更多类似的功能才能使用 Next 和 Prev 按钮 谢谢!但我也尝试允许鼠标滚动。【参考方案2】:

我找到了使用 SimpleBar 的解决方案:https://github.com/Grsmto/simplebar/tree/master/packages/simplebar

【讨论】:

以上是关于将水平滚动指示器添加到 DIV的主要内容,如果未能解决你的问题,请参考以下文章

UIScrollView - 将视图移到前面,但在滚动指示器下方

如何在nativescript angular中隐藏ios的水平滚动指示器

ListView 中的点指示器 Flutter 中的水平滚动

带有粘性水平指示器的 UICollectionView Swift 3.0

如何找出 ScrollView 滚动指示器的大小?

sencha touch 2 中的滚动条指示器可见性