Как мне прокрутить до элемента в переполненном Div?

159

У меня есть 20 элементов списка внутри div, которые могут показывать только 5 одновременно. Каков хороший способ прокрутки до пункта № 10, а затем до пункта № 20? Я знаю высоту всех предметов.

scrollToПлагин делает это, но его источник не очень легко понять , на самом деле не попасть в него. Я не хочу использовать этот плагин.

Скажем , у меня есть функция , которая принимает 2 элемента $parentDiv, $innerListItemни $innerListItem.offset().topни $innerListItem.positon().topдает мне правильный scrollTop за $ parentDiv.

mkoryak
источник
Удален мой ответ из-за вашего обновления. Но поверьте мне, у меня было такое же отношение раньше, есть много странностей в браузере с позицией и полями, и т. Д ... плагин - намного более простой маршрут и менее трудоемкий, и всего 3кб до GZip.
Ник Крейвер
1
В любом случае используйте плагин scrollTo. Это не трудно. $("#container").scrollTo(target, duration, options), Цель просто #anchor. Готово.
Райан Макгири
Похоже, что там должны быть знания, чтобы сделать это без плагина. завтра плохо начну читать источник
mkoryak
5
@mkoryak - Знание есть, но когда вы учитываете причуды браузера, вы в конечном итоге получаете ... плагин .scrollTo , так зачем все время изобретать колесо?
Ник Крейвер
1
ИМХО, вы, вероятно, в итоге получите именно то, что вам нужно из .scrollTo сегодня . Но через несколько месяцев, пока .scrollTo был обновлен до IE9, FF4 и Chrome 6, вам придется начинать сначала ... 3k кажется очень низкой ценой, чтобы избежать этого.
Вим

Ответы:

236

$innerListItem.position().topНа самом деле по отношению к .scrollTop()его первому позиционированному предку. Таким образом, способ рассчитать правильное $parentDiv.scrollTop()значение состоит в том, чтобы убедиться, что $parentDivон расположен. Если у него еще нет явного position, используйте position: relative. Элементы $innerListItemи все их предки до $parentDivнеобходимости не должны иметь явного положения. Теперь вы можете перейти к $innerListItem:

// Scroll to the top
$parentDiv.scrollTop($parentDiv.scrollTop() + $innerListItem.position().top);

// Scroll to the center
$parentDiv.scrollTop($parentDiv.scrollTop() + $innerListItem.position().top
    - $parentDiv.height()/2 + $innerListItem.height()/2);
Гленн Мосс
источник
152

Это мой собственный плагин (поместит элемент в начало списка. Специально для overflow-y : auto. Может не работать с overflow-x!):

ПРИМЕЧАНИЕ : elemэто HTML-селектор элемента, к которому будет прокручиваться страница. Все , что поддерживается JQuery, как: #myid, div.myclass, $(jquery object), [дом объект], и т.д.

jQuery.fn.scrollTo = function(elem, speed) { 
    $(this).animate({
        scrollTop:  $(this).scrollTop() - $(this).offset().top + $(elem).offset().top 
    }, speed == undefined ? 1000 : speed); 
    return this; 
};

Если вам не нужна анимация, используйте:

jQuery.fn.scrollTo = function(elem) { 
    $(this).scrollTop($(this).scrollTop() - $(this).offset().top + $(elem).offset().top); 
    return this; 
};

Как пользоваться:

$("#overflow_div").scrollTo("#innerItem");
$("#overflow_div").scrollTo("#innerItem", 2000); //custom animation speed 

Примечание: #innerItemможет быть где угодно внутри #overflow_div. Это не должно быть прямым ребенком.

Протестировано в Firefox (23) и Chrome (28).

Если вы хотите прокрутить всю страницу, проверьте этот вопрос .

Лепе
источник
что это elem?? Вы не объясняете это вообще.
vsync
Вы получаете лучший пробег / не конфликтуете, если вместо этого вы поменяете $ в fn.scrollTo на jQuery
Барри Карлион,
Большой недостаток в том, что вы не содержали сферу: $(this).scrollTop($(this).scrollTop() - $(this).offset().top + $(elem, $(this)).offset().top);- С уважением
Люк Сноуден
1
Если вы хотите оставить некоторый верхний предел между страницей и элементом (который может выглядеть лучше в некоторых случаях), вычитать, например, 10px, как: $(this).scrollTop() - $(this).offset().top + $(elem).offset().top - 10.
Лепе
Если у вас есть различия в позициях между Firefox и Chrome (или другими браузерами), проверьте ваш HTML-код (см. Этот отчет об ошибке )
lepe
34

Я изменил ответ Гленна Мосса, чтобы учесть тот факт, что переполнение div не может быть в верхней части страницы.

parentDiv.scrollTop(parentDiv.scrollTop() + (innerListItem.position().top - parentDiv.position().top) - (parentDiv.height()/2) + (innerListItem.height()/2)  )

Я использовал это в приложении Google Maps с адаптивным шаблоном. При разрешении> 800 пикселей список был на левой стороне карты. При разрешении <800 список был ниже карты.

KPheasey
источник
6

Приведенные выше ответы разместят внутренний элемент в верхней части элемента переполнения, даже если он находится внутри элемента переполнения. Я не хотел этого, поэтому я изменил его, чтобы не изменять позицию прокрутки, если элемент находится в поле зрения.

jQuery.fn.scrollTo = function(elem, speed) {
    var $this = jQuery(this);
    var $this_top = $this.offset().top;
    var $this_bottom = $this_top + $this.height();
    var $elem = jQuery(elem);
    var $elem_top = $elem.offset().top;
    var $elem_bottom = $elem_top + $elem.height();

    if ($elem_top > $this_top && $elem_bottom < $this_bottom) {
        // in view so don't do anything
        return;
    }
    var new_scroll_top;
    if ($elem_top < $this_top) {
        new_scroll_top = {scrollTop: $this.scrollTop() - $this_top + $elem_top};
    } else {
        new_scroll_top = {scrollTop: $elem_bottom - $this_bottom + $this.scrollTop()};
    }
    $this.animate(new_scroll_top, speed === undefined ? 100 : speed);
    return this;
};
Майк
источник
Это помогло мне! См. Stackoverflow.com/questions/48283932/…
ген b.
1

Я пишу эти две функции, чтобы сделать мою жизнь проще:

function scrollToTop(elem, parent, speed) {
    var scrollOffset = parent.scrollTop() + elem.offset().top;
    parent.animate({scrollTop:scrollOffset}, speed);
    // parent.scrollTop(scrollOffset, speed);
}

function scrollToCenter(elem, parent, speed) {
    var elOffset = elem.offset().top;
    var elHeight = elem.height();
    var parentViewTop = parent.offset().top;
    var parentHeight = parent.innerHeight();
    var offset;

    if (elHeight >= parentHeight) {
        offset = elOffset;
    } else {
        margin = (parentHeight - elHeight)/2;
        offset = elOffset - margin;
    }

    var scrollOffset = parent.scrollTop() + offset - parentViewTop;

    parent.animate({scrollTop:scrollOffset}, speed);
    // parent.scrollTop(scrollOffset, speed);
}

И использовать их:

scrollToTop($innerListItem, $parentDiv, 200);
// or
scrollToCenter($innerListItem, $parentDiv, 200);
Trank
источник
elem.offset().topрассчитывается с верхней части экрана. Я хочу, чтобы рассчитать из родительского элемента. Как я могу это сделать ?
Сантош
0

После долгой игры с этим я придумал:

    jQuery.fn.scrollTo = function (elem) {
        var b = $(elem);
        this.scrollTop(b.position().top + b.height() - this.height());
    };

и я называю это так

$("#basketListGridHolder").scrollTo('tr[data-uid="' + basketID + '"]');
Брюс Ривз
источник