我有一个设置,其中有一个标题,只有当可滚动区域的scrollTop为0时才显示(表示它们位于页面顶部)。在许多情况下,这似乎工作正常,但有一种情况是它以一种相当烦人的方式失败。
错误
如果可滚动区域中的内容稍微大到足以制作滚动条,那么当您向下滚动时,标题将消失,可滚动区域现在将增长以填充该空白区域,现在将允许内容在没有滚动条的情况下显示。 从滚动条到没有滚动条的过渡显然会在我测试过的所有浏览器中触发另一个滚动事件我不知道为什么会这样或如何解决它。
一种可能的解决方案
我可以将我的内容设置为最小高度为101%,这样无论实际内容高度如何,总会有少量滚动条。然而,这不是我最喜欢的解决方案,我正在寻找更好的东西。
HTML
<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 Fiddle JS Fiddle Example
答案 0 :(得分:1)
我做了一些改写,以使这更多Knockout-y和(希望)更直接一点。我将标题高度作为变量引入代码中,因为我需要使用它。
scrollTop
是一个受限制的可观察对象,因此它不会每250毫秒发布一次更新。
我使用observable和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>