Точно определить, прокручивается ли элемент
Я работаю над пользовательской привязкой нокаута, которая определяет, прокручивается ли конкретный элемент, и обновляет границу, наблюдаемую, с верхом элемента относительно области просмотра. Прямо сейчас привязка, кажется, работает, но у меня есть некоторые беспокойства о том, есть ли обстоятельства, когда это не будет.
HTML:
Scroll position: <span data-bind="text: scrollPosition"></span>
<div class="longdiv">
<p data-bind="scroll: scrollPosition">This is some text.</p>
<div class="shim"></div>
</div>
CSS:
.longdiv {
width: 200px;
height: 200px;
overflow: scroll;
border: 1px solid black;
}
JS:
ko.bindingHandlers.scroll = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var firstScrollableContainer = null;
var binding = allBindings.get('scroll');
$(element).parents().each(function (i, parent) {
if ($(parent).css('overflow')=='scroll') {
firstScrollableContainer = parent;
return false;
}
});
firstScrollableContainer = firstScrollableContainer || window;
binding(element.getBoundingClientRect().top);
$(firstScrollableContainer).scroll(function() {
binding(element.getBoundingClientRect().top);
});
}
};
var ViewModel = function() {
var self = this;
self.scrollPosition = ko.observable(0);
};
ko.applyBindings(new ViewModel());
JSFiddle
Привязка берет элемент и использует jQuery, чтобы пройти по родительской цепочке и посмотреть, есть ли у родительского элемента overflow: scroll set. Если он находит div с переполнением: scroll, он связывает обработчик события с этим событием прокрутки элемента. Если он не находит родителя с переполнением: scroll, он привязывается к событию прокрутки окна.
Итак, что я ищу, учитывая документ, структурированный так:
body > div > div > div > p
является ближайшим к p содержащим элементом, который можно прокручивать, чтобы я мог прикрепить к нему обработчик событий.
Мой вопрос: смотрит на переполнение: прокрутите достаточный тест, чтобы увидеть, можно ли прокрутить родительский элемент? Если нет, на что мне смотреть?
РЕДАКТИРОВАТЬ: На основе ваших полезных комментариев и ответов, вот решение, которое я придумал:
function scrollable(element) {
var vertically_scrollable, horizontally_scrollable;
var e = $(element);
if ( e.css('overflow') == 'scroll'
|| e.css('overflow') == 'auto'
|| e.css('overflowY') == 'scroll'
|| e.css('overflowY') == 'auto'
|| e.css('height') != 'none'
|| e.css('max-height') != 'none'
) {
return true;
} else {
return false;
}
}
Ответы
Ответ 1
Вы хотите узнать, может ли элемент прокручиваться или может прокручиваться в настоящее время?
Можно ли прокручивать элемент?
Элемент может прокручиваться, если он имеет фиксированный height
(или max-height
), а overflow-y
- scroll
или auto
. Но так как нелегко указать, если высота элемента фиксирована или нет, вероятно, достаточно просто проверить overflow-y
:
e.css('overflow-y') == 'scroll' || e.css('overflow-y') == 'auto'
Может ли элемент прокручиваться прямо сейчас?
Элемент может прокручиваться прямо сейчас, если его scrollHeight
больше его clientHeight
, и если у него есть полоса прокрутки, которая может быть определена путем сравнения clientWidth
и offsetWidth
(с учетом полей и границ) или если overflow-y
равен scroll
или auto
.
Ответ 2
Это, вероятно, самое безопасное решение (требуется jQuery, для простого JavaScript см. ниже):
$.fn.isHScrollable = function () {
return this[0].scrollWidth > this[0].clientWidth;
};
$.fn.isVScrollable = function () {
return this[0].scrollHeight > this[0].clientHeight;
};
$.fn.isScrollable = function () {
return this[0].scrollWidth > this[0].clientWidth || this[0].scrollHeight > this[0].clientHeight;
};
Затем вы можете проверить, можно ли прокрутить элемент следующим образом:
$(parent).isScrollable();
Для использования без jQuery вы можете реализовать такие функции:
function isScrollable(element) {
return element.scrollWidth > element.clientWidth || element.scrollHeight > element.clientHeight;
};
var myParent = document.getElementById('myParent')
isScrollable(myParent)
Ответ 3
Объединяя два ответа вместе и добавляя что-то свое, я использую это для проверки вертикальной прокрутки. Это может быть легко преобразовано для других случаев. (H & VH)
function isScrollable(e){
if( e.scrollTopMax !== undefined )
return e.scrollTopMax > 0; //All Hail Firefox and it superior technology!
if( e == document.scrollingElement ) //If what you're checking is BODY (or HTML depending on your css styles)
return e.scrollHeight > e.clientHeight; //This is a special case.
return e.scrollHeight > e.clientHeight && ["scroll", "auto"].indexOf(getComputedStyle(e).overflowY) >= 0
}
Я проверял это на Firefox и Chromium. Оба Linux. Вы все еще можете проверить их сами.