2016-03-11 4 views
19

У меня есть такая ситуация, когда мне нужно прокрутить элемент в окне просмотра. Проблема в том, что я не знаю, какой элемент прокручивается. Например, в Portrait тело прокручивается, а в Landscape - другой элемент (и есть больше ситуаций, которые изменяют прокручиваемый элемент)Найти первого прокручиваемого родителя

Теперь вопрос, заданный элементом, который необходимо прокрутить в окне просмотра, лучший способ найти свой первый прокручиваемый родитель?

Я установил демо here. С помощью кнопки вы можете переключаться между двумя различными ситуациями

<div class="outer"> 
    <div class="inner"> 
     <div class="content"> 
      ... 
      <span>Scroll me into view</span> 
     </div> 
    </div> 
</div> 

Тело прокручивать или .outer

Любые предложения?

ответ

22

Просто проверьте, если полоса прокрутки отображается, если не смотреть на родителя.

function getScrollParent(node) { 
    if (node == null) { 
    return null; 
    } 

    if (node.scrollHeight > node.clientHeight) { 
    return node; 
    } else { 
    return getScrollParent(node.parentNode); 
    } 
} 
+0

Если узел имеет 'inline' родителя,' clientHeight' будет 0, и он будет возвращен Вот. Лучше игнорировать узлы с 'clientHeight' 0. –

+2

Это хорошо, но не работает для узлов, которые переполнены, но все еще не могут прокручиваться. Если вы добавите чек на значение [overflowY] (https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#Determine_if_an_element_has_been_totally_scrolled), он, похоже, работает хорошо. 'let overflowY = window.getComputedStyle (node) .overflowY;' 'let isscrollable = overflowY! == 'visible' && overflowY! == 'hidden';' 'if (isScrollable && node.scrollHeight> node.clientHeight) {' – RustyToms

+0

Согласно @RustyToms и OP, я переписываю это: https://gist.github.com/twxia/bb20843c495a49644be6ea3804c0d775 – twxia

1

Я думаю, что вы хотите этого.

$('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) 
 
    \t 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>

8

Если вы используете JQuery UI вы можете использовать метод scrollParent. Посмотрите на API или source.

Из API:

.scrollParent(): Получить ближайший предок элемент, который прокручивать

Этот метод не принимает никаких аргументов. Этот метод находит ближайшего предка, который позволяет прокручивать. Другими словами, метод .scrollParent() находит элемент, в который будет прокручиваться текущий выбранный элемент .

Примечание: Этот метод работает только с объектами jQuery, содержащими один элемент.

Если вы не используете JQuery UI, но с помощью JQuery, то есть альтернативные независимые библиотеки, обеспечивающие аналогичные функциональные возможности, такие как:

jquery-scrollparent

+1

Я портировал это на vanilla JS здесь: http://stackoverflow.com/questions/35939886/ найти первый-прокручивать родителем # 42543908 –

16

Это чистый JS порт интерфейса JQuery scrollParent способ это cweston spoke of. Я пошел с этим, а не с решением принятого ответа, который не найдет родителя прокрутки, если до сих пор нет переполнения контента.

Единственное отличие моего порта в том, что если родительский объект не найден с правильным значением для свойства CSS overflow, я возвращаю элемент <body>. Пользовательский интерфейс JQuery вместо этого возвратил объект 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; 
} 
0

ответ с большинством голосов не работает во всех случаях scrollHeight > clientHeight, которые могут быть true, даже если не имеет скроллбара, я нашел это решение GIST 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); 
Смежные вопросы