相关容器内的 VelocityJS 滚动错误
VelocityJS Scrolling errors within relative containers
Velocity 在我的部分项目中有效,但我遇到的问题在 JSFiddle(下面的 link)中可重现,我认为它可能与问题 # 有某种关系项目 GitHub 页面上的 770。
(注意:我对这篇文章和下面的其他文章有 links,但没有 post 超过 2 links 的声誉,所以我很抱歉不得不查看这些。)
我想知道有没有人可以:
- 验证这是一个已知错误,
- 查看此问题的修复程序,
- 在我的实现中发现错误,或者
- 提供替代解决方案。
我正在构建一个实现 off-screen 推送菜单的网站,其中所有内容都包含在相对 DIV 中,该菜单使用 CSS 转换向右推送以显示菜单。有几个级别的相对定位的 DIVs 模拟我的站点 header 的固定定位(这是必要的,包含在推送菜单 DIV 中)。
推送菜单改编自 Codrops Playground 文章 (在 Tympanus.net 上搜索 "multi level push menu")。文章中有一个演示 linked。还有一个 link 说明了元素的虚假固定定位与文章中的 CSS 转换相结合(下半部分)。
我的开发站点上的菜单按预期工作。我从一些菜单项中实现 Velocity 以向下滚动到内部页面部分,这也很好用(从页面顶部滚动)。
但是,我还想从顶部的 fixed-position 侧边栏在页面内使用 Velocity 滚动,以允许用户单击部分标题以 auto-scroll 到那个部分。 不幸的是,侧边栏 link 仅在页面滚动到最顶部时才有效。 从任何其他滚动位置,link 无法正常工作.
如果页面向下滚动,单击任何 link 只会将页面进一步向下滚动,即使单击事件中请求的部分位于当前滚动位置之上。
此行为最能体现 Fiddle:
http://jsfiddle.net/Josefism/j4dLhssc/
基本站点结构
<div class="site-container">
<div class="menu-pusher">
<div class="scroller">
<div class="scroller-inner">
<div class="site-inner">
<div class="content-sidebar-wrap">
<main class="content">
<article class="page">
<div class="entry-content">
<div id="section-1" class="section-1">
<p>Spicy jalapeno bacon ipsum.</p>
<p>Cupim aliqua culpa bacon.</p>
<p>Aliqua irure qui chicken.</p>
</div><!-- End Section 1 -->
<div id="section-2" class="section-2">
<p>Spicy jalapeno bacon ipsum.</p>
<p>Cupim aliqua culpa bacon.</p>
<p>Aliqua irure qui chicken.</p>
</div><!-- End Section 2 -->
<div id="section-3" class="section-3">
<p>Spicy jalapeno bacon ipsum.</p>
<p>Cupim aliqua culpa bacon.</p>
<p>Aliqua irure qui chicken.</p>
</div><!-- End Section 3 -->
<div id="section-4" class="section-4">
<p>Spicy jalapeno bacon ipsum.</p>
<p>Cupim aliqua culpa bacon.</p>
<p>Aliqua irure qui chicken.</p>
</div><!-- End Section 4 -->
</div><!-- End Entry Content -->
</article>
</main>
<aside class="sidebar">
<section class="widget">
<div class="widget-wrap">
<div class="text-widget">
<ul class="sidebar-menu">
<li class="section-1-link">Section 1</li>
<li class="section-2-link">Section 2</li>
<li class="section-3-link">Section 3</li>
<li class="section-4-link">Section 4</li>
</ul>
</div><!-- End Text Widget -->
</div><!-- End Widget Wrap -->
</section>
</aside>
</div><!-- End Content Sidebar Wrap -->
</div><!-- End Site Inner -->
</div><!-- End Scroller Inner -->
</div><!-- End Scroller -->
</div><!-- End Menu Pusher -->
</div><!-- End Site Container -->
CSS(为适应JSFiddle重现问题而修改)
body {
font-family: Helvetica;
width: 95%;
margin: 0 auto;
color: white;
background: red;
height: 100%;
overflow: hidden;
}
.site-container {
position: relative;
overflow: hidden;
height: 100%;
margin-top: 90px;
}
.menu-pusher {
position: relative;
left: 0;
height: 100%;
}
.scroller {
position: relative;
overflow-y: scroll;
height: 400px;
}
.scroller-inner {
position: relative;
}
.site-inner {
position: relative;
}
main {
display: block;
}
.content {
float: right;
}
.content-sidebar-wrap .content {
width: 100%;
}
.sidebar {
float: left;
width: 100%;
top: 0px;
position: fixed;
display: block;
}
.sidebar .widget {
padding: 20px;
display: block;
background-color: #CCC;
color: #FFF;
}
.sidebar-menu {
text-align: center;
}
.sidebar-menu li {
list-style-type: none;
padding: 0 1%;
cursor: pointer;
display: inline-block;
}
.sidebar-menu li:hover,
.sidebar-menu li.hovered {
color: green;
}
.page {
display: block;
}
.section-1 {
background-color: #ddd;
color: #000;
padding: 20px 20px 100px 20px;
}
.section-2 {
background-color: #FFF;
color: #000;
padding: 20px 20px 100px 20px;
}
.section-3 {
background-color: #AAA;
color: #FFF;
padding: 20px 20px 100px 20px;
}
.section-4 {
background-color: #555;
color: #FFF;
padding: 20px 20px 100px 20px;
margin-bottom: 100px;
}
jQuery Velocity 实现(不包括菜单项中的我的 Velocity 实现,因为它们已经可以工作了。)
$(document).ready(function(e) {
// Add Velocity scrolling to the internal section sidebar links
$(".section-1-link").on("click", function() {
$("#section-1").velocity("stop", true).velocity("scroll", {
container: $(".scroller"),
duration: 1000,
easing: "easeInOutSine",
delay: 300,
offset: 1
});
});
$(".section-2-link").on("click", function() {
$("#section-2").velocity("stop", true).velocity("scroll", {
container: $(".scroller"),
duration: 1000,
easing: "easeInOutSine",
delay: 300,
offset: 1
});
});
$(".section-3-link").on("click", function() {
$("#section-3").velocity("stop", true).velocity("scroll", {
container: $(".scroller"),
duration: 1000,
easing: "easeInOutSine",
delay: 300,
offset: 1
});
});
$(".section-4-link").on("click", function() {
$("#section-4").velocity("stop", true).velocity("scroll", {
container: $(".scroller"),
duration: 1000,
easing: "easeInOutSine",
delay: 300,
offset: 1
});
});
// Callback to section menu in primary sidebar to indicate scroll position
$(".scroller").on("scroll", function() {
var scrollerTop = $(".scroller").scrollTop();
var section1TopDist = $("#section-1").offset().top;
var section2TopDist = $("#section-2").offset().top;
var section3TopDist = $("#section-3").offset().top;
var section4TopDist = $("#section-4").offset().top;
if (section4TopDist < 90) {
$(".section-2-link, .section-3-link, .section-1-link").removeClass("hovered");
$(".section-4-link").addClass("hovered");
} else if (section3TopDist < 90) {
$(".section-2-link, .section-1-link, .section-4-link").removeClass("hovered");
$(".section-3-link").addClass("hovered");
} else if (section2TopDist < 90) {
$(".section-1-link, .section-3-link, .section-4-link").removeClass("hovered");
$(".section-2-link").addClass("hovered");
} else if (section1TopDist < 90) {
$(".section-2-link, .section-3-link, .section-4-link").removeClass("hovered");
$(".section-1-link").addClass("hovered");
} else {
$(".section-1-link, .section-2-link, .section-3-link, .section-4-link").removeClass("hovered");
}
});
});
好吧,经过一些测试和故障排除后,我找出了导致问题的原因。如果使用 Velocity.js 的其他人在包含元素内滚动时遇到类似问题,我将在此处发布我的解决方案作为故障排除参考。
正如下面代码块中的注释所指出的,问题是 "scrollPositionCurrent" 被添加到新的滚动位置并丢弃了返回的总数。从计算中删除它对我有用,现在在包含元素内滚动按预期工作。
从那以后,我在其他网站上使用我修改过的 Velocity.js 文件来滚动没有包含元素的整个页面,并且仍然可以正常工作。
以下代码块来自几天前(2017 年 10 月中旬)GitHub 上 Velocity.js 当前版本的第 3171-3205 行。
原始代码仍存在于代码段中以供参考,但已被注释掉。
/* Scroll also uniquely takes an optional "container" option, which indicates the parent element that should be scrolled --
as opposed to the browser window itself. This is useful for scrolling toward an element that's inside an overflowing parent element. */
if (opts.container) {
/* Ensure that either a jQuery object or a raw DOM element was passed in. */
if (Type.isWrapped(opts.container) || Type.isNode(opts.container)) {
console.log("GOT IT!");
/* Extract the raw DOM element from the jQuery wrapper. */
opts.container = opts.container[0] || opts.container;
/* Note: Unlike other properties in Velocity, the browser's scroll position is never cached since it so frequently changes
(due to the user's natural interaction with the page). */
scrollPositionCurrent = opts.container["scroll" + scrollDirection]; /* GET */
/* $.position() values are relative to the container's currently viewable area (without taking into account the container's true dimensions
-- say, for example, if the container was not overflowing). Thus, the scroll end value is the sum of the child element's position *and*
the scroll container's current scroll position. */
/* scrollPositionEnd = (scrollPositionCurrent + $(element).position()[scrollDirection.toLowerCase()]) + scrollOffset; */ /* GET */
/* CORRECTION - Applied by Josef Cook
Scroll position of element within a containing element was incorrect. Adding current scroll position blows out the total.
Had to remove current scroll position addition (commented out above) to make this work correctly. */
scrollPositionEnd = ($(element).position()[scrollDirection.toLowerCase()]) + scrollOffset;
/* If a value other than a jQuery object or a raw DOM element was passed in, default to null so that this option is ignored. */
} else {
opts.container = null;
}
} else {
/* If the window itself is being scrolled -- not a containing element -- perform a live scroll position lookup using
the appropriate cached property names (which differ based on browser type). */
scrollPositionCurrent = Velocity.State.scrollAnchor[Velocity.State["scrollProperty" + scrollDirection]]; /* GET */
/* When scrolling the browser window, cache the alternate axis's current value since window.scrollTo() doesn't let us change only one value at a time. */
scrollPositionCurrentAlternate = Velocity.State.scrollAnchor[Velocity.State["scrollProperty" + (scrollDirection === "Left" ? "Top" : "Left")]]; /* GET */
/* Unlike $.position(), $.offset() values are relative to the browser window's true dimensions -- not merely its currently viewable area --
and therefore end values do not need to be compounded onto current values. */
scrollPositionEnd = $(element).offset()[scrollDirection.toLowerCase()] + scrollOffset; /* GET */
}
Velocity 在我的部分项目中有效,但我遇到的问题在 JSFiddle(下面的 link)中可重现,我认为它可能与问题 # 有某种关系项目 GitHub 页面上的 770。
(注意:我对这篇文章和下面的其他文章有 links,但没有 post 超过 2 links 的声誉,所以我很抱歉不得不查看这些。)
我想知道有没有人可以:
- 验证这是一个已知错误,
- 查看此问题的修复程序,
- 在我的实现中发现错误,或者
- 提供替代解决方案。
我正在构建一个实现 off-screen 推送菜单的网站,其中所有内容都包含在相对 DIV 中,该菜单使用 CSS 转换向右推送以显示菜单。有几个级别的相对定位的 DIVs 模拟我的站点 header 的固定定位(这是必要的,包含在推送菜单 DIV 中)。
推送菜单改编自 Codrops Playground 文章 (在 Tympanus.net 上搜索 "multi level push menu")。文章中有一个演示 linked。还有一个 link 说明了元素的虚假固定定位与文章中的 CSS 转换相结合(下半部分)。
我的开发站点上的菜单按预期工作。我从一些菜单项中实现 Velocity 以向下滚动到内部页面部分,这也很好用(从页面顶部滚动)。
但是,我还想从顶部的 fixed-position 侧边栏在页面内使用 Velocity 滚动,以允许用户单击部分标题以 auto-scroll 到那个部分。 不幸的是,侧边栏 link 仅在页面滚动到最顶部时才有效。 从任何其他滚动位置,link 无法正常工作.
如果页面向下滚动,单击任何 link 只会将页面进一步向下滚动,即使单击事件中请求的部分位于当前滚动位置之上。
此行为最能体现 Fiddle: http://jsfiddle.net/Josefism/j4dLhssc/
基本站点结构
<div class="site-container">
<div class="menu-pusher">
<div class="scroller">
<div class="scroller-inner">
<div class="site-inner">
<div class="content-sidebar-wrap">
<main class="content">
<article class="page">
<div class="entry-content">
<div id="section-1" class="section-1">
<p>Spicy jalapeno bacon ipsum.</p>
<p>Cupim aliqua culpa bacon.</p>
<p>Aliqua irure qui chicken.</p>
</div><!-- End Section 1 -->
<div id="section-2" class="section-2">
<p>Spicy jalapeno bacon ipsum.</p>
<p>Cupim aliqua culpa bacon.</p>
<p>Aliqua irure qui chicken.</p>
</div><!-- End Section 2 -->
<div id="section-3" class="section-3">
<p>Spicy jalapeno bacon ipsum.</p>
<p>Cupim aliqua culpa bacon.</p>
<p>Aliqua irure qui chicken.</p>
</div><!-- End Section 3 -->
<div id="section-4" class="section-4">
<p>Spicy jalapeno bacon ipsum.</p>
<p>Cupim aliqua culpa bacon.</p>
<p>Aliqua irure qui chicken.</p>
</div><!-- End Section 4 -->
</div><!-- End Entry Content -->
</article>
</main>
<aside class="sidebar">
<section class="widget">
<div class="widget-wrap">
<div class="text-widget">
<ul class="sidebar-menu">
<li class="section-1-link">Section 1</li>
<li class="section-2-link">Section 2</li>
<li class="section-3-link">Section 3</li>
<li class="section-4-link">Section 4</li>
</ul>
</div><!-- End Text Widget -->
</div><!-- End Widget Wrap -->
</section>
</aside>
</div><!-- End Content Sidebar Wrap -->
</div><!-- End Site Inner -->
</div><!-- End Scroller Inner -->
</div><!-- End Scroller -->
</div><!-- End Menu Pusher -->
</div><!-- End Site Container -->
CSS(为适应JSFiddle重现问题而修改)
body {
font-family: Helvetica;
width: 95%;
margin: 0 auto;
color: white;
background: red;
height: 100%;
overflow: hidden;
}
.site-container {
position: relative;
overflow: hidden;
height: 100%;
margin-top: 90px;
}
.menu-pusher {
position: relative;
left: 0;
height: 100%;
}
.scroller {
position: relative;
overflow-y: scroll;
height: 400px;
}
.scroller-inner {
position: relative;
}
.site-inner {
position: relative;
}
main {
display: block;
}
.content {
float: right;
}
.content-sidebar-wrap .content {
width: 100%;
}
.sidebar {
float: left;
width: 100%;
top: 0px;
position: fixed;
display: block;
}
.sidebar .widget {
padding: 20px;
display: block;
background-color: #CCC;
color: #FFF;
}
.sidebar-menu {
text-align: center;
}
.sidebar-menu li {
list-style-type: none;
padding: 0 1%;
cursor: pointer;
display: inline-block;
}
.sidebar-menu li:hover,
.sidebar-menu li.hovered {
color: green;
}
.page {
display: block;
}
.section-1 {
background-color: #ddd;
color: #000;
padding: 20px 20px 100px 20px;
}
.section-2 {
background-color: #FFF;
color: #000;
padding: 20px 20px 100px 20px;
}
.section-3 {
background-color: #AAA;
color: #FFF;
padding: 20px 20px 100px 20px;
}
.section-4 {
background-color: #555;
color: #FFF;
padding: 20px 20px 100px 20px;
margin-bottom: 100px;
}
jQuery Velocity 实现(不包括菜单项中的我的 Velocity 实现,因为它们已经可以工作了。)
$(document).ready(function(e) {
// Add Velocity scrolling to the internal section sidebar links
$(".section-1-link").on("click", function() {
$("#section-1").velocity("stop", true).velocity("scroll", {
container: $(".scroller"),
duration: 1000,
easing: "easeInOutSine",
delay: 300,
offset: 1
});
});
$(".section-2-link").on("click", function() {
$("#section-2").velocity("stop", true).velocity("scroll", {
container: $(".scroller"),
duration: 1000,
easing: "easeInOutSine",
delay: 300,
offset: 1
});
});
$(".section-3-link").on("click", function() {
$("#section-3").velocity("stop", true).velocity("scroll", {
container: $(".scroller"),
duration: 1000,
easing: "easeInOutSine",
delay: 300,
offset: 1
});
});
$(".section-4-link").on("click", function() {
$("#section-4").velocity("stop", true).velocity("scroll", {
container: $(".scroller"),
duration: 1000,
easing: "easeInOutSine",
delay: 300,
offset: 1
});
});
// Callback to section menu in primary sidebar to indicate scroll position
$(".scroller").on("scroll", function() {
var scrollerTop = $(".scroller").scrollTop();
var section1TopDist = $("#section-1").offset().top;
var section2TopDist = $("#section-2").offset().top;
var section3TopDist = $("#section-3").offset().top;
var section4TopDist = $("#section-4").offset().top;
if (section4TopDist < 90) {
$(".section-2-link, .section-3-link, .section-1-link").removeClass("hovered");
$(".section-4-link").addClass("hovered");
} else if (section3TopDist < 90) {
$(".section-2-link, .section-1-link, .section-4-link").removeClass("hovered");
$(".section-3-link").addClass("hovered");
} else if (section2TopDist < 90) {
$(".section-1-link, .section-3-link, .section-4-link").removeClass("hovered");
$(".section-2-link").addClass("hovered");
} else if (section1TopDist < 90) {
$(".section-2-link, .section-3-link, .section-4-link").removeClass("hovered");
$(".section-1-link").addClass("hovered");
} else {
$(".section-1-link, .section-2-link, .section-3-link, .section-4-link").removeClass("hovered");
}
});
});
好吧,经过一些测试和故障排除后,我找出了导致问题的原因。如果使用 Velocity.js 的其他人在包含元素内滚动时遇到类似问题,我将在此处发布我的解决方案作为故障排除参考。
正如下面代码块中的注释所指出的,问题是 "scrollPositionCurrent" 被添加到新的滚动位置并丢弃了返回的总数。从计算中删除它对我有用,现在在包含元素内滚动按预期工作。
从那以后,我在其他网站上使用我修改过的 Velocity.js 文件来滚动没有包含元素的整个页面,并且仍然可以正常工作。
以下代码块来自几天前(2017 年 10 月中旬)GitHub 上 Velocity.js 当前版本的第 3171-3205 行。
原始代码仍存在于代码段中以供参考,但已被注释掉。
/* Scroll also uniquely takes an optional "container" option, which indicates the parent element that should be scrolled --
as opposed to the browser window itself. This is useful for scrolling toward an element that's inside an overflowing parent element. */
if (opts.container) {
/* Ensure that either a jQuery object or a raw DOM element was passed in. */
if (Type.isWrapped(opts.container) || Type.isNode(opts.container)) {
console.log("GOT IT!");
/* Extract the raw DOM element from the jQuery wrapper. */
opts.container = opts.container[0] || opts.container;
/* Note: Unlike other properties in Velocity, the browser's scroll position is never cached since it so frequently changes
(due to the user's natural interaction with the page). */
scrollPositionCurrent = opts.container["scroll" + scrollDirection]; /* GET */
/* $.position() values are relative to the container's currently viewable area (without taking into account the container's true dimensions
-- say, for example, if the container was not overflowing). Thus, the scroll end value is the sum of the child element's position *and*
the scroll container's current scroll position. */
/* scrollPositionEnd = (scrollPositionCurrent + $(element).position()[scrollDirection.toLowerCase()]) + scrollOffset; */ /* GET */
/* CORRECTION - Applied by Josef Cook
Scroll position of element within a containing element was incorrect. Adding current scroll position blows out the total.
Had to remove current scroll position addition (commented out above) to make this work correctly. */
scrollPositionEnd = ($(element).position()[scrollDirection.toLowerCase()]) + scrollOffset;
/* If a value other than a jQuery object or a raw DOM element was passed in, default to null so that this option is ignored. */
} else {
opts.container = null;
}
} else {
/* If the window itself is being scrolled -- not a containing element -- perform a live scroll position lookup using
the appropriate cached property names (which differ based on browser type). */
scrollPositionCurrent = Velocity.State.scrollAnchor[Velocity.State["scrollProperty" + scrollDirection]]; /* GET */
/* When scrolling the browser window, cache the alternate axis's current value since window.scrollTo() doesn't let us change only one value at a time. */
scrollPositionCurrentAlternate = Velocity.State.scrollAnchor[Velocity.State["scrollProperty" + (scrollDirection === "Left" ? "Top" : "Left")]]; /* GET */
/* Unlike $.position(), $.offset() values are relative to the browser window's true dimensions -- not merely its currently viewable area --
and therefore end values do not need to be compounded onto current values. */
scrollPositionEnd = $(element).offset()[scrollDirection.toLowerCase()] + scrollOffset; /* GET */
}