【问题标题】:Freeze selected item when scrolling滚动时冻结所选项目
【发布时间】:2015-07-16 07:51:35
【问题描述】:

我有一个要求,当所选项目位于容器的顶部折叠时,我需要将所选项目从容器中的项目列表冻结到顶部。当所选项目处于容器的底部折叠时,我需要将其粘在底部。

如果所选项目在可见折叠中,则不会发生任何事情。我的意思是所选项目应该与其他相邻项目正常流动。

我在某种程度上设法解决了这个问题。但是当我向上滚动时,当所选项目粘贴在容器上方时,所选项目被隐藏。即使当我向下滚动时,当所选项目粘在容器底部时,也会发生这种行为。

Here is the Fiddle

$('.item').click(function () {
    $('.item').removeClass('select').removeClass('pAbsolute');
    $(this).addClass('select');
});

$('.parent').scroll(function () {
    var $selected = $('.item.select');
    var cTop = $selected.offset().top;
    var cHeight = $selected.height();
    var pHeight = $(this).height();
    if (cTop < 0) {
        $selected.css({
            'top': $(this).scrollTop(),
                'bottom': ''
        }).addClass('pAbsolute');
    } else if (cTop > pHeight - cHeight) {
        $selected.css({
            'bottom': -$(this).scrollTop(),
                'top': ''
        }).addClass('pAbsolute');
    } else {
        $selected.css({
            'top': '',
                'bottom': ''
        }).removeClass('pAbsolute');
    }
});

【问题讨论】:

  • 您可以选择多少个项目?您的小提琴显示了两个“已选择”的元素(1 和 22)。
  • @JackPattishall 一次只有一个。 我更新了小提琴这是一个错误

标签: javascript jquery html css scroll


【解决方案1】:

您必须使用一致的值来保持选择时相对于容器的初始偏移量。

然后,计算偏移量和滚动值,

  1. 如果 cTop

  2. 如果cTop + cHeight > pHeight,表示它的视图超出底部块,设置为底部。

  3. 否则保持原位。

编辑:

在选择新项目时,正如上一个项目可能有.pAbsolute attr,当前项目的相对位置可能会改变,但我们可以通过跟踪这些类添加/删除操作之前和之后的偏移量来获得偏移更改。

然后我们可以通过手动改变容器的scrollTop来添加缺失的高度。

var offset;
$('.item').click(function () {
    // This is the offset in container before class change.
    offset = this.offsetTop;
    $('.item').removeClass('select').removeClass('pAbsolute');
    $(this).addClass('select');
    // Calculate the difference
    var distortion = offset - this.offsetTop;
    
    // Remove the distortion by manual scroll.
    var $parent = $(this).parent();
    $parent.scrollTop($parent.scrollTop() - distortion);
    
    offset = this.offsetTop;
});


$('.parent').scroll(function () {
    var $selected = $('.item.select');
    var cTop = offset - $(this).scrollTop();
    var cHeight = $selected.height();
    var pHeight = $(this).height();
    if (cTop < 0) {
        $selected.css({
            'top': $(this).scrollTop(),
                'bottom': ''
        }).addClass('pAbsolute');
    } else if (cTop + cHeight > pHeight) {
        $selected.css({
            'bottom': -$(this).scrollTop(),
                'top': ''
        }).addClass('pAbsolute');
    } else {
        $selected.css({
            'top': '',
                'bottom': ''
        }).removeClass('pAbsolute');
    }
});
body, html {
    padding: 0;
    margin: 0;
}
.parent {
    overflow: auto;
    height: 200px;
    position: relative;
}
.item {
    padding: 10px 15px;
    background-color: tomato;
    width: 100%;
}
.item.select {
    background-color: beige;
}
.pAbsolute {
    position: absolute;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parent">
    <div class="item select">1</div>
    <div class="item">2</div>
    <div class="item">3</div>
    <div class="item">4</div>
    <div class="item">5</div>
    <div class="item">6</div>
    <div class="item">7</div>
    <div class="item">8</div>
    <div class="item">9</div>
    <div class="item">10</div>
    <div class="item">11</div>
    <div class="item">12</div>
    <div class="item">13</div>
    <div class="item">14</div>
    <div class="item">15</div>
    <div class="item">16</div>
    <div class="item">17</div>
    <div class="item">18</div>
    <div class="item">19</div>
    <div class="item">20</div>
    <div class="item">21</div>
    <div class="item">22</div>
    <div class="item">23</div>
    <div class="item">24</div>
    <div class="item">25</div>
    <div class="item">26</div>
    <div class="item">27</div>
    <div class="item">28</div>
    <div class="item">29</div>
    <div class="item">30</div>
    <div class="item">31</div>
    <div class="item">32</div>
    <div class="item">33</div>
    <div class="item">34</div>
    <div class="item">35</div>
    <div class="item">36</div>
    <div class="item">37</div>
    <div class="item">38</div>
    <div class="item">39</div>
    <div class="item">40</div>
    <div class="item">41</div>
</div>

【讨论】:

  • 谢谢,这实际上比我上面显示的更有效。仍然存在一些问题,例如:当我单击一个项目时,该项目的位置正在移动。这肯定会让用户感到困惑。我也会在这里尝试修复它。再次感谢您。 :)
  • 我认为我们需要将每个项目包装在一个包装器中以保持高度。但就我而言,我不能这样做,因为高度不固定。
  • 我有了一些想法,尝试使用 jsfiddle。
【解决方案2】:

此解决方案使用底部和顶部标题,填充所选值并在必要时显示/隐藏:

Working Fiddle

Javascript:

function stickItems($parent, itemClass, selectClass) {
    // Attach dummy element items
    $parent.prepend('<div class="' + itemClass + ' sticky top"></div>');
    $parent.append('<div class="' + itemClass + ' sticky bottom"></div>');

    var $items = $('.' + itemClass),
        $stickyTop = $('.' + itemClass + '.sticky.top'),
        $stickyBottom = $('.' + itemClass + '.sticky.bottom');

    // Click event registering 
    $items.click(function (e) {
        if (!$(e.target).hasClass('sticky')) {
            $items.removeClass(selectClass);
            $stickyTop.css('display', 'none');
            $stickyBottom.css('display', 'none');
            $(this).addClass(selectClass);
        }
    });



    // Scroll event
    $parent.scroll(function () {
        var $self = $(this);
        var $selected = $('.' + itemClass + '.' + selectClass);
        var cTop = $selected.offset().top;
        var pTop = $self.offset().top;
        var cHeight = $selected.height();
        var pHeight = $self.height();
        if (cTop - pTop <= 0) {
            $stickyTop.html($selected.html()).css({
                'display': 'block',
                    'top': $(this).scrollTop()
            });
            $stickyBottom.css('display', 'none');
        } else if (cTop > pTop && cTop < pTop + pHeight) {
            $stickyTop.css('display', 'none');
            $stickyBottom.css('display', 'none');
        } else {
            $stickyTop.css('display', 'none');
            $stickyBottom.html($selected.html()).css({
                'display': 'block',
                    'bottom': -$(this).scrollTop()
            });
        }
    });
}

stickItems($('.parent'), 'item', 'select');

CSS:

body, html {
    padding: 0;
    margin: 0;
}
body {
    padding-top: 200px;
}
.parent {
    overflow-x: hidden;
    overflow-y: auto;
    height: 200px;
    position: relative;
}
.item {
    padding: 10px 15px;
    background-color: tomato;
}
.item.select {
    background-color: beige;
}
.item.sticky {
    background-color: beige;
    display: none;
    position: absolute;
    left: 0;
    right: 0;
    z-index: 1;
}

HTML:

<div class="parent">
    <div class="item sticky top"></div>
    <div class="item select">1</div>
    <div class="item">2</div>
    <!-- ... -->
    <div class="item">39</div>
    <div class="item">40</div>
    <div class="item">41</div>
    <div class="item sticky bottom"></div>
</div>

【讨论】:

  • 向你的想法致敬 :)
  • 此解决方案工作正常,但如果容器顶部有间隙,我可以看到两个具有相同内容的选定项目。请检查此fiddle。我修改了代码,但没有修改概念。
  • 我解决了。这是Fiddle。如果你不介意,我会更新你的帖子。 (不喜欢就回滚
  • 干得好!抱歉,我现在没有更多时间研究它。
猜你喜欢
  • 1970-01-01
  • 2018-06-26
  • 1970-01-01
  • 1970-01-01
  • 2011-04-04
  • 1970-01-01
  • 2010-12-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多