在页面顶部显示标题-滚动事件重新触发问题

Show header when at top of page - Scroll event re-firing issue

本文关键字:事件 滚动 新触发 问题 标题 顶部 显示      更新时间:2023-09-26

我有一个设置,在那里,有一个标题,这将只显示当滚动区域的scrollTop为0(意味着他们在页面的顶部)。在许多情况下,这似乎工作得很好,但也有一种情况,它以一种相当恼人的方式失败。

错误

如果在可滚动区域的内容只是稍微大到足以使一个滚动条,那么当你向下滚动,标题将消失,可滚动区域现在将增长,以填补空白的空间,这现在将允许内容显示没有滚动条。从拥有滚动条到没有滚动条的过渡显然会触发另一个滚动事件,在我测试过的所有浏览器中触发我不知道为什么会这样,也不知道如何解决它。

一个可能的解

我可以将内容的最小高度设置为101%,这样无论实际内容的高度是多少,都会有少量的滚动条。然而,这不是我最喜欢的解决方案,我正在寻找更好的解决方案。

<div class="container">
<div class="header">Header</div>
<div class="content" data-bind="css: {'show-header': showHeader}">
    <div class="sub-header">Sub Header</div>
    <div class="scrollable" data-bind="event: {'scroll':test}">
        <div class="stuff">asdf</div>       
    </div>
</div>

CSS

    .container {
    position: absolute;
    top: 0;
    left: 0;
    width: 320px;
    height: 352px;
    border: 1px solid black;
}
.header {
    height: 48px;
    background: grey;
}
.content {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    transition: top 0.3s;
}
.show-header {
 top: 48px;   
}

.sub-header {
    height: 48px;
    background: lightgrey;
}
.scrollable {
    position: absolute;
    top: 48px;
    left: 0;
    right: 0;
    bottom: 0;
    overflow: auto;
    -webkit-overflow-scrolling: touch;
    overflow-x: hidden;
}
.stuff {
    /*min-height: 101%;*/
    height: 260px;
    /*height: 2000px;*/
}

JS

    var appViewModel = {};
var didScroll = false;
var scrollElem = $('.scrollable');
appViewModel.showHeader = ko.observable(true);
appViewModel.test = function() {
    didScroll = true;
};

setInterval(function() {
    if (didScroll) {
        didScroll = false;
        appViewModel.hasScrolled();
    }
}, 250);

appViewModel.hasScrolled = function() {
    var st = scrollElem.scrollTop();
    if ( st > 0 && appViewModel.showHeader() ) {
        appViewModel.showHeader(false);
    }
    else if ( st <= 0 && !appViewModel.showHeader() ) {
        appViewModel.showHeader(true);
    }
};

ko.applyBindings(appViewModel);

JS小提琴JS提琴示例

我做了一些重写,使这个更Knockout-y和(希望)更直接一点。我把标题的高度作为一个变量带入代码,因为我需要使用它。

scrollTop是一个节流的可观察对象,所以它不会超过每250毫秒宣布一次更新

我使用一个可观察对象和一个if绑定来控制头是否被渲染。当scrollTop改变时,一个订阅函数决定是否应该显示标题。计算取决于当前是否显示标题。

scrollableHeight控制可滚动区域的高度,如果标题被隐藏则扩展可滚动区域。

我所知道的避免滚动条消失的问题的唯一方法是只有在滚动超过标题高度时才删除标题。

var appViewModel = {};
var didScroll = false;
appViewModel.headerHeight = 48;
appViewModel.scrollTop = ko.observable(0).extend({rateLimit:250});
appViewModel.showHeader = ko.observable(true);
appViewModel.scrollTop.subscribe(function (newTop) {
    console.debug("New top");
    if (appViewModel.showHeader()) {
        appViewModel.showHeader(newTop < appViewModel.headerHeight);
    }
    else {
        appViewModel.showHeader(newTop <= 0);
    }
});
appViewModel.scrollableHeight = ko.computed(function () {
    return (appViewModel.showHeader()) ? '256px' : (256 + appViewModel.headerHeight) + 'px';
});
appViewModel.test = function (data, event) {
    var scrollElem = $(event.target);
    appViewModel.scrollTop(scrollElem.scrollTop());
};
ko.applyBindings(appViewModel);
.container {
  position: absolute;
  top: 0;
  left: 0;
  width: 320px;
  height: 352px;
  border: 1px solid black;
}
.header {
  background: grey;
}
.sub-header {
  height: 48px;
  background: lightgrey;
}
.scrollable {
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overflow-x: hidden;
  height: 256px;
}
.stuff {
  background-color: #fee;
  height: 320px;
  /*height: 2000px;*/
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div class="container">
  <!-- ko if:showHeader -->
  <div class="header" data-bind="style:{height:headerHeight+'px'}">Header</div>
  <!-- /ko -->
  <div class="sub-header">Sub Header</div>
  <div class="scrollable" data-bind="style:{height:scrollableHeight}, event: {'scroll':test}">
    <div class="stuff">asdf</div>
  </div>
</div>