查找第一个可滚动的父项
Find first scrollable parent
我遇到这种情况,我需要将元素滚动到视口中。问题是我不知道哪个元素是可滚动的。例如,在纵向中,身体是可滚动的,而在横向中是另一个元素(并且还有更多情况会更改可滚动元素)
现在的问题是,给定一个需要滚动到视口中的元素,找到其第一个可滚动父元素的最佳方法是什么?
我在这里设置了一个演示。使用按钮,您可以在两种不同的情况之间切换
<div class="outer">
<div class="inner">
<div class="content">
...
<span>Scroll me into view</span>
</div>
</div>
</div>
正文可滚动或.outer
有什么建议吗?
只需检查滚动条是否可见,如果不查看父级。
function getScrollParent(node) {
if (node == null) {
return null;
}
if (node.scrollHeight > node.clientHeight) {
return node;
} else {
return getScrollParent(node.parentNode);
}
}
cweston所说的jQuery UI scrollParent
方法的纯JS端口。我选择了这个而不是接受的答案的解决方案,如果还没有内容溢出,则找不到滚动父级。
与我的端口的一个区别是,如果没有找到具有 CSS overflow
属性正确值的父级,我将返回 <body>
元素。JQuery UI,而是返回document
对象。这很奇怪,因为像.scrollTop
这样的值可以从<body>
中检索,但不能从document
中检索。
function getScrollParent(element, includeHidden) {
var style = getComputedStyle(element);
var excludeStaticParent = style.position === "absolute";
var overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/;
if (style.position === "fixed") return document.body;
for (var parent = element; (parent = parent.parentElement);) {
style = getComputedStyle(parent);
if (excludeStaticParent && style.position === "static") {
continue;
}
if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX)) return parent;
}
return document.body;
}
投票的答案并非在所有情况下都有效scrollHeight > clientHeight
即使没有滚动条也可以true
。
我发现这个要点解决方案 https://github.com/olahol/scrollparent.js/blob/master/scrollparent.js#L13
^ 总功劳归于编写代码 https://github.com/olahol。
将其重构为es6
:
export const getScrollParent = (node) => {
const regex = /(auto|scroll)/;
const parents = (_node, ps) => {
if (_node.parentNode === null) { return ps; }
return parents(_node.parentNode, ps.concat([_node]));
};
const style = (_node, prop) => getComputedStyle(_node, null).getPropertyValue(prop);
const overflow = _node => style(_node, 'overflow') + style(_node, 'overflow-y') + style(_node, 'overflow-x');
const scroll = _node => regex.test(overflow(_node));
/* eslint-disable consistent-return */
const scrollParent = (_node) => {
if (!(_node instanceof HTMLElement || _node instanceof SVGElement)) {
return;
}
const ps = parents(_node.parentNode, []);
for (let i = 0; i < ps.length; i += 1) {
if (scroll(ps[i])) {
return ps[i];
}
}
return document.scrollingElement || document.documentElement;
};
return scrollParent(node);
/* eslint-enable consistent-return */
};
您可以像这样使用它:
const $yourElement = document.querySelector('.your-class-or-selector');
getScrollParent($yourElement);
如果你使用的是jQuery UI,你可以使用scrollParent
方法。查看 API 或源代码。
从 API :
如果您没有使用 jQuery
.scrollParent()
:获取可滚动的最接近的祖先元素此方法不接受任何参数。此方法 查找允许滚动的最近祖先。换句话说,
.scrollParent()
方法查找当前选定的元素 元素将在内部滚动。注意:此方法仅适用于包含一个元素的 jQuery 对象。
UI,而是使用 jQuery,那么还有其他提供类似功能的独立库,例如:
jquery-scrollparent
使用谷歌浏览器开发工具,当您部分向下滚动页面时,检查页面,选择您认为可能是正在滚动的 DOM 节点。然后拉起控制台(从开发工具的"元素"选项卡中点击 ESC)并键入 $0.scrollTop
。这将打印出该元素的当前滚动位置。如果它不是 0,那么您将知道这是正在滚动的元素。
我想你想要这个。
$('button').click(function() {
$("body").addClass("body");
$('.outer').toggleClass('scroller');
check($(".content"));
});
function check(el) {
var overflowY = el.css("overflow-y");
if (overflowY == "scroll") {
alert(el.attr("class") + " has");
} else {
if(el.parent().length > 0)
check(el.parent());
else
return false;
}
}
body {
height: 450px;
overflow-y: scroll;
}
div.inner {
width: 200px;
height: 400px;
border: 1px solid #000;
}
div.outer {
width: 200px;
height: 200px;
}
div.outer.scroller {
overflow-y: scroll;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>
toggle
</button>
<div class="outer">
<div class="inner">
<div class="content">
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." adipiscing elit, sed do eiusmod tempor incididunt ut
labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur
sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
</div>
</div>
</div>
进一步基于@Web_Designer的答案,
如果您正在传递该元素的jQuery object
并收到以下错误,
Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'
然后尝试只传递 btw 驻留在数组键0
的Dom Node element
如果元素是单个元素。例如。
getScrollParent(jQuery("#" + formid)[0])
这就是我目前所拥有的似乎适用于 Web 组件自定义元素 shadowRoots; 我们可以进一步扩展它,以便在滚动开始卸载此处理并跟踪特定节点的滚动事件后添加滚动事件处理程序
function scroller(node){ return node.scrollTop }
function handler(event){
const path = event.composedPath();
const scrollNode = path.find(scroller);
const scrollNodes = path.filter(scroller);
console.warn('scroll!',{scrollNode, scrollNodes});
}
window.addEventListener('mousewheel', handler, {capture: true});
window.addEventListener('keydown', handler, {capture: true});
@ncubica答案的更有效版本。
在这个版本中,我们逐个检查每个父项,并停在第一个可滚动的父项上。此外,每个父级只调用一次getComputedStyle()
。
const isScrollable = (node: Element) => {
if (!(node instanceof HTMLElement || node instanceof SVGElement)) {
return false
}
const style = getComputedStyle(node)
return ['overflow', 'overflow-x', 'overflow-y'].some((propertyName) => {
const value = style.getPropertyValue(propertyName)
return value === 'auto' || value === 'scroll'
})
}
export const getScrollParent = (node: Element): Element => {
let currentParent = node.parentElement
while (currentParent) {
if (isScrollable(currentParent)) {
return currentParent
}
currentParent = currentParent.parentElement
}
return document.scrollingElement || document.documentElement
}
这是找到你想要的东西的方法。
document.addEventListener('scroll', (e) => {
console.log(e.target.scrollingElement.scrollTop);
})
- 而循环只设置php中输入字段中的第一个值
- 错误:$injector:modulerr模块错误(我的第一个SPA应用程序)
- IE11中的第二个调用取消了第一个Fetch API调用
- Javascript XMLHttpRequest——只有第一个POST请求有效
- 使用javascript或angularjs特定过滤器搜索字符串中第一个img标记的json值
- 将OnClick函数设置为<ul>,最后一个ul是擦除第一个ul-s
- RxJS油门行为;立即获取第一个值
- Angular UI网格:如何通过第一个UI网格中的按钮使第二个UI网格可见
- 选择多个实例中的第一个
- 如何在调用下一个请求之前完成第一个Ajax Get请求
- Lodash:返回对象的第一个键,该对象的值(即数组)中有一个给定的元素(即字符串)
- 看起来第一个console.log是'It’不太对
- 与杜兰达尔合作的第一个JavaScript项目.尝试从第三方 API 获取数据
- 节点发布错误对象的第一个“属性”
- Javascript:表单验证getElementById仅返回第一个id元素
- 仅将 CSS 规则应用于
中的第一个 ,而不分配类/ID - JS在隐藏未定义的值后仅从数组中返回第一个id的值
- 高图表,检测点是否在堆栈中的第一个
- 当移动到最后一个li时,返回到第一个li(使用Jquery滚动到下一个)
- Jquery scrollTop将只滚动到第一个id,而不会滚动到其他id