Làm cách nào để cuộn đến một phần tử trong Div tràn?


159

Tôi có 20 mục danh sách bên trong một div chỉ có thể hiển thị 5 mục một lần. Cách tốt để cuộn đến mục số 10, rồi mục 20 là gì? Tôi biết chiều cao của tất cả các mặt hàng.

Các scrollToPlugin thực hiện điều này, nhưng nguồn gốc của nó không phải là siêu dễ hiểu mà không thực sự nhận được vào nó. Tôi không muốn sử dụng plugin này.

Hãy nói rằng tôi có một hàm mang theo 2 yếu tố $parentDiv, $innerListItem, không phải $innerListItem.offset().topvà cũng không $innerListItem.positon().topmang lại cho tôi những scrollTop đúng với $ parentDiv.


Đã xóa câu trả lời của tôi do cập nhật của bạn. Nhưng tin tôi đi, trước đây cũng có thái độ tương tự, có rất nhiều quirks trình duyệt với vị trí và lề, v.v ... plugin là một tuyến đường đơn giản hơn nhiều và ít tốn thời gian hơn, và chỉ 3k trước GZip.
Nick Craver

1
Sử dụng plugin scrollTo nào. Nó không khó. $("#container").scrollTo(target, duration, options). Mục tiêu chỉ là một #anchor. Làm xong.
Ryan McGeary

Có vẻ như cần có kiến ​​thức ngoài kia để làm điều này mà không cần plugin. ngày mai bắt đầu đọc nguồn
mkoryak

5
@mkoryak - Kiến thức đã có, nhưng khi bạn tính đến các yêu cầu của trình duyệt, về cơ bản bạn sẽ kết thúc với ... plugin .scrollTo , vậy tại sao lại phát minh lại bánh xe?
Nick Craver

1
IMHO, có lẽ bạn sẽ kết thúc với tập hợp con chính xác của những gì bạn cần từ .scrollĐến hôm nay . Nhưng trong một vài tháng, trong khi .scrollTo đã được cập nhật lên IE9, FF4 và Chrome 6, bạn sẽ phải bắt đầu lại ... 3k có vẻ như là một mức giá rất thấp để tránh điều này.
Wim 27/210

Câu trả lời:


236

Điều $innerListItem.position().topnày thực sự liên quan đến .scrollTop()tổ tiên định vị đầu tiên của nó. Vì vậy, cách tính $parentDiv.scrollTop()giá trị chính xác là bắt đầu bằng cách đảm bảo rằng nó $parentDivđược định vị. Nếu nó không có một rõ ràng position, sử dụng position: relative. Các yếu tố $innerListItemvà tất cả tổ tiên của nó $parentDivcần phải không có vị trí rõ ràng. Bây giờ bạn có thể cuộn đến $innerListItemvới:

// 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

Đây là plugin của riêng tôi (sẽ đặt phần tử vào đầu danh sách. Đặc biệt là overflow-y : auto. Có thể không hoạt động vớioverflow-x !):

LƯU Ý : elemlà bộ chọn HTML của một thành phần mà trang sẽ được cuộn đến. Bất cứ điều gì được hỗ trợ bởi jQuery, như: #myid, div.myclass, $(jquery object), [đối tượng dom], vv

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

Nếu bạn không cần nó để hoạt hình, thì hãy sử dụng:

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

Cách sử dụng:

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

Lưu ý: #innerItemcó thể ở bất cứ đâu bên trong #overflow_div. Nó không thực sự phải là một đứa trẻ trực tiếp.

Đã thử nghiệm trên Firefox (23) và Chrome (28).

Nếu bạn muốn cuộn toàn bộ trang, hãy kiểm tra câu hỏi này .


là gì elem?? bạn không giải thích gì cả
vsync

Thay vào đó, bạn nhận được số dặm tốt hơn / không xung đột nếu bạn trao đổi $ trong fn.scrollTo thành jQuery
Barry Carlyon

Lỗ hổng lớn với điều này, bạn không chứa phạm vi: $(this).scrollTop($(this).scrollTop() - $(this).offset().top + $(elem, $(this)).offset().top);- liên quan
Luke Snowden

1
Nếu bạn muốn để lại một số lề trên giữa trang và phần tử (có thể trông tốt hơn trong một số trường hợp), hãy trừ, ví dụ, 10px, như : $(this).scrollTop() - $(this).offset().top + $(elem).offset().top - 10.
lepe

Nếu bạn có sự khác biệt về vị trí giữa Firefox và Chrome (hoặc các trình duyệt khác), hãy kiểm tra mã html của bạn (xem báo cáo lỗi này )
lepe

34

Tôi đã điều chỉnh câu trả lời của Glenn Moss để giải thích cho thực tế rằng div tràn có thể không ở đầu trang.

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

Tôi đã sử dụng điều này trên một ứng dụng google maps với một mẫu phản hồi. Ở độ phân giải> 800px, danh sách nằm ở bên trái bản đồ. Trên độ phân giải <800, danh sách nằm bên dưới bản đồ.


6

Các câu trả lời ở trên sẽ định vị phần tử bên trong ở trên cùng của phần tử tràn ngay cả khi nó nằm trong phần tử bên trong phần tử tràn. Tôi không muốn điều đó vì vậy tôi đã sửa đổi nó để không thay đổi vị trí cuộn nếu phần tử đang được xem.

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;
};

Điều này đã giúp tôi !! Xem stackoverflow.com/questions/48283932/ cường
gen b.

1

Tôi viết 2 chức năng này để làm cho cuộc sống của tôi dễ dàng hơn:

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);
}

Và sử dụng chúng:

scrollToTop($innerListItem, $parentDiv, 200);
// or
scrollToCenter($innerListItem, $parentDiv, 200);

elem.offset().topđang tính toán từ trên cùng của màn hình. Tôi muốn tính toán đó từ phần tử cha. Làm thế nào để làm điều đó ?
Santosh

0

Sau khi chơi với nó trong một thời gian rất dài, đây là những gì tôi nghĩ ra:

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

và tôi gọi nó như thế này

$("#basketListGridHolder").scrollTo('tr[data-uid="' + basketID + '"]');
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.