Làm thế nào để cuộn đến một phần tử bên trong div?


170

Tôi có một cuộn divvà tôi muốn có một liên kết khi tôi nhấp vào nó, nó sẽ buộc nó divphải cuộn để xem một phần tử bên trong. Tôi đã viết JavasSript của nó như thế này:

document.getElementById(chr).scrollIntoView(true);

nhưng điều này cuộn tất cả các trang trong khi cuộn divchính nó. Làm thế nào để khắc phục điều đó?

Tôi muốn nói như thế

MyContainerDiv.getElementById(chr).scrollIntoView(true);

Scrolltop không luôn luôn trả về một giá trị có thể sử dụng. Tôi có xu hướng sử dụng một SetTimeouttrong $(document).ready({})hàm và đặt thành focus()phần tử bạn muốn cuộn. Làm việc cho tôi
DerpyNerd

Câu trả lời:


340

Bạn cần lấy phần bù trên cùng của phần tử bạn muốn cuộn vào chế độ xem, liên quan đến phần tử mẹ của nó (bộ chứa div cuộn):

var myElement = document.getElementById('element_within_div');
var topPos = myElement.offsetTop;

Biến topPos hiện được đặt thành khoảng cách giữa đỉnh div cuộn và phần tử bạn muốn hiển thị (tính bằng pixel).

Bây giờ chúng tôi bảo div di chuyển đến vị trí đó bằng cách sử dụng scrollTop:

document.getElementById('scrolling_div').scrollTop = topPos;

Nếu bạn đang sử dụng khung công tác JS nguyên mẫu, bạn sẽ làm điều tương tự như sau:

var posArray = $('element_within_div').positionedOffset();
$('scrolling_div').scrollTop = posArray[1];

Một lần nữa, điều này sẽ cuộn div để phần tử bạn muốn thấy chính xác ở trên cùng (hoặc nếu điều đó là không thể, hãy cuộn xuống càng xa càng tốt để nó hiển thị).


9
Điều này thực sự hữu ích! Nếu bạn muốn đặt cuộn nhiều lần, bạn cần phải bù theo vị trí cuộn hiện tại của mình. Đây là cách tôi đã làm trong jQuery: $ ('# scrolling_div'). ScrollTop ($ ('# scrolling_div'). ScrollTop () + $ ('# Element_within_div'). Position (). Top);
Sẽ

3
Coi chừng việc yêu cầu myElement.offsetTopsẽ kích hoạt chỉnh lại dòng (đập bố cục) có thể là nút cổ chai hiệu năng
Kestutis

27
Hãy nhớ đặt cha mẹ cuộn với css: position: relativenếu không bạn sẽ mất rất nhiều thời gian để gỡ lỗi như tôi vừa làm.
saveario

2
Tôi đã phải đặt thuộc overflow-ytính scrollcho phần tử cha ( scrolling_div), nếu không nó không hoạt động. Giá trị css mặc định cho thuộc overflowtính là autovà mặc dù nó cũng có thể cuộn thủ công, mã js sẽ không hoạt động (ngay cả với {psition: relative}..)
Evgenia Manolova

2
Vẫn hoạt động vào năm 2017. Thông tin bổ sung: .offsetTop có thể trả về 0. Sau đó, bạn nên tham khảo phần tử cha và thử lại. Tôi đã làm điều đó cho các thẻ h4sau divđó articlegắn thẻ và chỉ articlelàm việc cho tôi.
Fenio

66

Bạn sẽ phải tìm vị trí của phần tử trong DIV mà bạn muốn cuộn và đặt thuộc tính scrollTop.

divElem.scrollTop = 0;

Cập nhật :

Mã mẫu để di chuyển lên hoặc xuống

  function move_up() {
    document.getElementById('divElem').scrollTop += 10;
  }

  function move_down() {
    document.getElementById('divElem').scrollTop -= 10;
  }

3
Tôi muốn cuộn nó để xem, để xem nó không cuộn với một giá trị nhất định
Amr Elgarhy

39

Phương pháp 1 - Di chuyển mượt mà đến một phần tử bên trong một phần tử

var box = document.querySelector('.box'),
    targetElm = document.querySelector('.boxChild'); // <-- Scroll to here within ".box"

document.querySelector('button').addEventListener('click', function(){
   scrollToElm( box, targetElm , 600 );   
});


/////////////

function scrollToElm(container, elm, duration){
  var pos = getRelativePos(elm);
  scrollTo( container, pos.top , 2);  // duration in seconds
}

function getRelativePos(elm){
  var pPos = elm.parentNode.getBoundingClientRect(), // parent pos
      cPos = elm.getBoundingClientRect(), // target pos
      pos = {};

  pos.top    = cPos.top    - pPos.top + elm.parentNode.scrollTop,
  pos.right  = cPos.right  - pPos.right,
  pos.bottom = cPos.bottom - pPos.bottom,
  pos.left   = cPos.left   - pPos.left;

  return pos;
}
    
function scrollTo(element, to, duration, onDone) {
    var start = element.scrollTop,
        change = to - start,
        startTime = performance.now(),
        val, now, elapsed, t;

    function animateScroll(){
        now = performance.now();
        elapsed = (now - startTime)/1000;
        t = (elapsed/duration);

        element.scrollTop = start + change * easeInOutQuad(t);

        if( t < 1 )
            window.requestAnimationFrame(animateScroll);
        else
            onDone && onDone();
    };

    animateScroll();
}

function easeInOutQuad(t){ return t<.5 ? 2*t*t : -1+(4-2*t)*t };
.box{ width:80%; border:2px dashed; height:180px; overflow:auto; }
.boxChild{ 
  margin:600px 0 300px; 
  width: 40px;
  height:40px;
  background:green;
}
<button>Scroll to element</button>
<div class='box'>
  <div class='boxChild'></div>
</div>

Phương pháp 2 - Sử dụng Element.scrollIntoView :

Lưu ý rằng hỗ trợ trình duyệt không tốt cho cái này

var targetElm = document.querySelector('.boxChild'),  // reference to scroll target
    button = document.querySelector('button');        // button that triggers the scroll
  
// bind "click" event to a button 
button.addEventListener('click', function(){
   targetElm.scrollIntoView()
})
.box {
  width: 80%;
  border: 2px dashed;
  height: 180px;
  overflow: auto;
  scroll-behavior: smooth; /* <-- for smooth scroll */
}

.boxChild {
  margin: 600px 0 300px;
  width: 40px;
  height: 40px;
  background: green;
}
<button>Scroll to element</button>
<div class='box'>
  <div class='boxChild'></div>
</div>

Phương pháp 3 - Sử dụng hành vi cuộn CSS :

.box {
  width: 80%;
  border: 2px dashed;
  height: 180px;
  overflow-y: scroll;
  scroll-behavior: smooth; /* <--- */
}

#boxChild {
  margin: 600px 0 300px;
  width: 40px;
  height: 40px;
  background: green;
}
<a href='#boxChild'>Scroll to element</a>
<div class='box'>
  <div id='boxChild'></div>
</div>


1
Lưu ý rằng cuộn hành vi không được hỗ trợ trong IE / Edge / Safari
sheats

1
@sheats - Nó nói chính xác rằng trong liên kết tài liệu MDN mà tôi đã đặt ở cỡ chữ lớn. Ngay cả khi nó không hoạt động cho các trình duyệt đó, điều đó không có nghĩa là bạn không nên sử dụng nó. Không có "quy tắc" nào, mọi thứ phải hoạt động giống nhau trên tất cả các trình duyệt. Nếu các trình duyệt hiện đại có thể làm phép thuật, hãy để chúng làm phép thuật.
vsync

Bài đăng này là về việc cuộn toàn bộ tài liệu chứ không phải là một yếu tố có thể cuộn.

@ DoMiNeLa10 - Đó là một giả định. OP có thể đã cung cấp một ví dụ tùy ý nhằm minh họa vấn đề của anh ấy / cô ấy. Ngoài ra, OP không phải là mối quan tâm chính mà là những người đến từ các công cụ tìm kiếm đang tìm kiếm một giải pháp lành mạnh và rất có thể việc trả lời cụ thể cho các nhu cầu của OP sẽ không giúp được họ, và mục đích của trang web này là tạo ra những câu trả lời chắc chắn có thể giúp ích cho nhiều người càng tốt Câu trả lời của tôi cung cấp cả hai .
vsync

12

Để cuộn một phần tử vào chế độ xem của div, chỉ khi cần, bạn có thể sử dụng scrollIfNeededchức năng này :

function scrollIfNeeded(element, container) {
  if (element.offsetTop < container.scrollTop) {
    container.scrollTop = element.offsetTop;
  } else {
    const offsetBottom = element.offsetTop + element.offsetHeight;
    const scrollBottom = container.scrollTop + container.offsetHeight;
    if (offsetBottom > scrollBottom) {
      container.scrollTop = offsetBottom - container.offsetHeight;
    }
  }
}

document.getElementById('btn').addEventListener('click', ev => {
  ev.preventDefault();
  scrollIfNeeded(document.getElementById('goose'), document.getElementById('container'));
});
.scrollContainer {
  overflow-y: auto;
  max-height: 100px;
  position: relative;
  border: 1px solid red;
  width: 120px;
}

body {
  padding: 10px;
}

.box {
  margin: 5px;
  background-color: yellow;
  height: 25px;
  display: flex;
  align-items: center;
  justify-content: center;
}

#goose {
  background-color: lime;
}
<div id="container" class="scrollContainer">
  <div class="box">duck</div>
  <div class="box">duck</div>
  <div class="box">duck</div>
  <div class="box">duck</div>
  <div class="box">duck</div>
  <div class="box">duck</div>
  <div class="box">duck</div>
  <div class="box">duck</div>
  <div id="goose" class="box">goose</div>
  <div class="box">duck</div>
  <div class="box">duck</div>
  <div class="box">duck</div>
  <div class="box">duck</div>
</div>

<button id="btn">scroll to goose</button>


1
Điều này thực sự hữu ích. Tôi vật lộn một chút vì tôi đã bỏ lỡ vị trí: tương đối trên container. Đó là rất quan trọng!
brohr

11

Mã phải là:

var divElem = document.getElementById('scrolling_div');
var chElem = document.getElementById('element_within_div');
var topPos = divElem.offsetTop;
divElem.scrollTop = topPos - chElem.offsetTop;

Bạn muốn cuộn sự khác biệt giữa vị trí trên cùng của con và vị trí trên cùng của div.

Truy cập vào các phần tử con bằng cách sử dụng:

var divElem = document.getElementById('scrolling_div'); 
var numChildren = divElem.childNodes.length;

và như thế....


1
Không nên đọc dòng thứ 2 var chElem = document.getElementById('element_within_div');và dòng thứ 3 có nên đọc var topPos = divElem.offsetTop;không?
jayp

7

Nếu bạn đang sử dụng jQuery, bạn có thể cuộn với một hình ảnh động bằng cách sử dụng như sau:

$(MyContainerDiv).animate({scrollTop: $(MyContainerDiv).scrollTop() + ($('element_within_div').offset().top - $(MyContainerDiv).offset().top)});

Hoạt hình là tùy chọn: bạn cũng có thể lấy giá trị scrollTop được tính toán ở trên và đặt trực tiếp vào thuộc tính scrollTop của bộ chứa .


5

Mã nguồn gốc, Trình duyệt chéo, Cuộn mượt (Cập nhật 2020)

Cài đặt ScrollTopkhông cho kết quả mong muốn nhưng cuộn rất đột ngột. Sử dụng jqueryđể có cuộn trơn tru không phải là một lựa chọn. Vì vậy, đây là một cách tự nhiên để hoàn thành công việc hỗ trợ tất cả các trình duyệt chính. Tham khảo - caniuse

// get the "Div" inside which you wish to scroll (i.e. the container element)
const El = document.getElementById('xyz');

// Lets say you wish to scroll by 100px, 
El.scrollTo({top: 100, behavior: 'smooth'});

// If you wish to scroll until the end of the container
El.scrollTo({top: El.scrollHeight, behavior: 'smooth'});

Đó là nó!


Và đây là một đoạn làm việc cho những người nghi ngờ -

document.getElementById('btn').addEventListener('click', e => {
  e.preventDefault();
  // smooth scroll
  document.getElementById('container').scrollTo({top: 175, behavior: 'smooth'});
});
/* just some styling for you to ignore */
.scrollContainer {
  overflow-y: auto;
  max-height: 100px;
  position: relative;
  border: 1px solid red;
  width: 120px;
}

body {
  padding: 10px;
}

.box {
  margin: 5px;
  background-color: yellow;
  height: 25px;
  display: flex;
  align-items: center;
  justify-content: center;
}

#goose {
  background-color: lime;
}
<!-- Dummy html to be ignored -->
<div id="container" class="scrollContainer">
  <div class="box">duck</div>
  <div class="box">duck</div>
  <div class="box">duck</div>
  <div class="box">duck</div>
  <div class="box">duck</div>
  <div class="box">duck</div>
  <div class="box">duck</div>
  <div class="box">duck</div>
  <div id="goose" class="box">goose</div>
  <div class="box">duck</div>
  <div class="box">duck</div>
  <div class="box">duck</div>
  <div class="box">duck</div>
</div>

<button id="btn">goose</button>

Cập nhật: Như bạn có thể nhận thấy trong các bình luận, có vẻ như điều đó Element.scrollTo()không được hỗ trợ trong IE11. Vì vậy, nếu bạn không quan tâm đến IE11 (bạn thực sự không nên), hãy sử dụng nó trong tất cả các dự án của bạn. Lưu ý rằng hỗ trợ tồn tại cho Edge! Vì vậy, bạn không thực sự bỏ lại người dùng Edge / Windows của mình;)

Tài liệu tham khảo


1
scrollTo()có thể được hỗ trợ trong tất cả các trình duyệt chính cho Windowcác đối tượng nhưng không được hỗ trợ trong IE hoặc Edge cho các thành phần.
Tim xuống

Theo caniuse , nó được hỗ trợ trong IE11 và Edge. Không được thử nghiệm cá nhân trên các trình duyệt này, nhưng dường như nó được hỗ trợ.
Niket Pathak

1
Đó là window.scrollTo, không phải Element.scrollTo. Ví dụ, hãy thử điều này trong Edge và kiểm tra bảng điều khiển: codepen.io/timdown/pen/abzVEMB
Tim Down

bạn đúng rồi. IE11 không được hỗ trợ. Tuy nhiên, Edge v76 (ref) trở lên dường như được hỗ trợ
Niket Pathak

2

Có hai sự thật:

1) Thành phần scrollIntoView không được safari hỗ trợ.

2) jQuery framework jQuery có thể thực hiện công việc như thế này:

parent = 'some parent div has css position==="fixed"' || 'html, body';

$(parent).animate({scrollTop: $(child).offset().top}, duration)

1

Đây là một giải pháp JavaScript thuần túy đơn giản hoạt động cho Số mục tiêu (giá trị cho scrollTop), phần tử DOM đích hoặc một số trường hợp Chuỗi đặc biệt:

/**
 * target - target to scroll to (DOM element, scrollTop Number, 'top', or 'bottom'
 * containerEl - DOM element for the container with scrollbars
 */
var scrollToTarget = function(target, containerEl) {
    // Moved up here for readability:
    var isElement = target && target.nodeType === 1,
        isNumber = Object.prototype.toString.call(target) === '[object Number]';

    if (isElement) {
        containerEl.scrollTop = target.offsetTop;
    } else if (isNumber) {
        containerEl.scrollTop = target;
    } else if (target === 'bottom') {
        containerEl.scrollTop = containerEl.scrollHeight - containerEl.offsetHeight;
    } else if (target === 'top') {
        containerEl.scrollTop = 0;
    }
};

Và đây là một số ví dụ về cách sử dụng:

// Scroll to the top
var scrollableDiv = document.getElementById('scrollable_div');
scrollToTarget('top', scrollableDiv);

hoặc là

// Scroll to 200px from the top
var scrollableDiv = document.getElementById('scrollable_div');
scrollToTarget(200, scrollableDiv);

hoặc là

// Scroll to targetElement
var scrollableDiv = document.getElementById('scrollable_div');
var targetElement= document.getElementById('target_element');
scrollToTarget(targetElement, scrollableDiv);

1

Một ví dụ khác về việc sử dụng jQuery và hoạt hình.

var container = $('#container');
var element = $('#element');

container.animate({
    scrollTop: container.scrollTop = container.scrollTop() + element.offset().top - container.offset().top
}, {
    duration: 1000,
    specialEasing: {
        width: 'linear',
        height: 'easeOutBounce'
    },
    complete: function (e) {
        console.log("animation completed");
    }
});

0

Cuộn hoạt hình người dùng

Đây là một ví dụ về cách cuộn chương trình <div>theo chiều ngang mà không cần JQuery . Để cuộn theo chiều dọc, bạn sẽ thay thế ghi Javascript để scrollLeftscrollTop, để thay thế.

Câu đố

https://jsfiddle.net/fNPvf/38536/

HTML

<!-- Left Button. -->
<div style="float:left;">
    <!-- (1) Whilst it's pressed, increment the scroll. When we release, clear the timer to stop recursive scroll calls. -->
    <input type="button" value="«" style="height: 100px;" onmousedown="scroll('scroller',3, 10);" onmouseup="clearTimeout(TIMER_SCROLL);"/>
</div>
<!-- Contents to scroll. -->
<div id="scroller" style="float: left; width: 100px; height: 100px; overflow: hidden;">
    <!-- <3 -->
    <img src="https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-logo.png?v=9c558ec15d8a" alt="image large" style="height: 100px" />
</div>
<!-- Right Button. -->
<div style="float:left;">
    <!-- As (1). (Use a negative value of 'd' to decrease the scroll.) -->
    <input type="button" value="»" style="height: 100px;" onmousedown="scroll('scroller',-3, 10);" onmouseup="clearTimeout(TIMER_SCROLL);"/>
</div>

JavaScript

// Declare the Shared Timer.
var TIMER_SCROLL;
/** 
Scroll function. 
@param id  Unique id of element to scroll.
@param d   Amount of pixels to scroll per sleep.
@param del Size of the sleep (ms).*/
function scroll(id, d, del){
    // Scroll the element.
    document.getElementById(id).scrollLeft += d;
    // Perform a delay before recursing this function again.
    TIMER_SCROLL = setTimeout("scroll('"+id+"',"+d+", "+del+");", del);
 }

Tín dụng cho Dux .


Tự động cuộn

Ngoài ra, đây là các chức năng để cuộn <div>hoàn toàn sang trái và phải. Điều duy nhất chúng tôi thay đổi ở đây là chúng tôi thực hiện kiểm tra xem liệu phần mở rộng đầy đủ của cuộn đã được sử dụng trước khi thực hiện cuộc gọi đệ quy để cuộn lại.

Câu đố

https://jsfiddle.net/0nLc2fhh/1/

HTML

<!-- Left Button. -->
<div style="float:left;">
    <!-- (1) Whilst it's pressed, increment the scroll. When we release, clear the timer to stop recursive scroll calls. -->
    <input type="button" value="«" style="height: 100px;" onclick="scrollFullyLeft('scroller',3, 10);"/>
</div>
<!-- Contents to scroll. -->
<div id="scroller" style="float: left; width: 100px; height: 100px; overflow: hidden;">
  <!-- <3 -->
  <img src="https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-logo.png?v=9c558ec15d8a" alt="image large" style="height: 100px" />
</div>
<!-- Right Button. -->
<div style="float:left;">
    <!-- As (1). (Use a negative value of 'd' to decrease the scroll.) -->
    <input type="button" value="»" style="height: 100px;" onclick="scrollFullyRight('scroller',3, 10);"/>
</div>

JavaScript

// Declare the Shared Timer.
var TIMER_SCROLL;
/** 
Scroll fully left function; completely scrolls  a <div> to the left, as far as it will go.
@param id  Unique id of element to scroll.
@param d   Amount of pixels to scroll per sleep.
@param del Size of the sleep (ms).*/
function scrollFullyLeft(id, d, del){
    // Fetch the element.
    var el = document.getElementById(id);
    // Scroll the element.
    el.scrollLeft += d;
    // Have we not finished scrolling yet?
    if(el.scrollLeft < (el.scrollWidth - el.clientWidth)) {
        TIMER_SCROLL = setTimeout("scrollFullyLeft('"+id+"',"+d+", "+del+");", del);
    }
}

/** 
Scroll fully right function; completely scrolls  a <div> to the right, as far as it will go.
@param id  Unique id of element to scroll.
@param d   Amount of pixels to scroll per sleep.
@param del Size of the sleep (ms).*/
function scrollFullyRight(id, d, del){
    // Fetch the element.
    var el = document.getElementById(id);
    // Scroll the element.
    el.scrollLeft -= d;
    // Have we not finished scrolling yet?
    if(el.scrollLeft > 0) {
        TIMER_SCROLL = setTimeout("scrollFullyRight('"+id+"',"+d+", "+del+");", del);
    }
}

0

Đây là những gì cuối cùng đã phục vụ tôi

/** Set parent scroll to show element
 * @param element {object} The HTML object to show
 * @param parent {object} The HTML object where the element is shown  */
var scrollToView = function(element, parent) {
    //Algorithm: Accumulate the height of the previous elements and add half the height of the parent
    var offsetAccumulator = 0;
    parent = $(parent);
    parent.children().each(function() {
        if(this == element) {
            return false; //brake each loop
        }
        offsetAccumulator += $(this).innerHeight();
    });
    parent.scrollTop(offsetAccumulator - parent.innerHeight()/2);
}

0

trình duyệt sẽ tự động cuộn đến một phần tử được lấy nét, vì vậy bạn cũng có thể làm điều đó để bọc phần tử mà bạn cần cuộn vào <a>...</a>và sau đó khi bạn cần cuộn, hãy đặt tiêu điểm vào đóa


0

Sau khi chọn phần tử, chỉ cần sử dụng scrollIntoViewchức năng với tùy chọn bên dưới:

const option = {
  top: 0, // number,
  left: 0, // number,
  behavior: 'auto', // auto or smooth 
    // - auto for one jump motion and smooth for animated motion -
};

Vì vậy, câu trả lời cho bài viết này là:

const el = document.getElementById('id-name');
el.scrollIntoView({
  top: 0,
  left: 0,
  behavior: 'auto',
});

0

nếu bạn có một phần tử div bạn cần cuộn vào bên trong, hãy thử đoạn mã này

document.querySelector('div').scroll(x,y)

cái này hoạt động với tôi bên trong div với một cuộn, cái này sẽ hoạt động với bạn trong trường hợp bạn hướng con chuột qua phần tử này và sau đó cố gắng cuộn xuống hoặc lên. Nếu nó hoạt động bằng tay, nó cũng hoạt động

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.