Bagaimana cara menggulir ke elemen di dalam div?

170

Saya telah menggulir divdan saya ingin memiliki tautan ketika saya mengkliknya, ini akan memaksa ini divuntuk menggulir untuk melihat elemen di dalamnya. Saya menulis JavasSript-nya seperti ini:

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

tapi ini menggulung semua halaman sambil menggulirnya divsendiri. Bagaimana cara memperbaikinya?

Saya ingin mengatakannya seperti itu

MyContainerDiv.getElementById(chr).scrollIntoView(true);
Amr Elgarhy
sumber
Scrolltop tidak selalu mengembalikan nilai yang dapat digunakan. Saya cenderung menggunakan SetTimeoutdalam $(document).ready({})fungsi dan set focus()ke elemen Anda ingin untuk menggulir ke. Bekerja untuk saya
DerpyNerd

Jawaban:

340

Anda perlu mendapatkan offset atas elemen yang ingin Anda gulir ke tampilan, relatif terhadap induknya (wadah div gulir):

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

Variabel topPos sekarang diatur ke jarak antara bagian atas div pengguliran dan elemen yang ingin Anda lihat (dalam piksel).

Sekarang kami memberitahu div untuk menggulir ke posisi itu menggunakan scrollTop:

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

Jika Anda menggunakan kerangka JS prototipe, Anda akan melakukan hal yang sama seperti ini:

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

Sekali lagi, ini akan menggulir div sehingga elemen yang ingin Anda lihat persis di atas (atau jika itu tidak mungkin, gulir sejauh mungkin sehingga dapat terlihat).

Brian Barrett
sumber
9
Ini sangat membantu! Jika Anda ingin mengatur gulir beberapa kali, Anda perlu mengimbangi dengan lokasi gulir Anda saat ini. Begini caranya saya melakukannya di jQuery: $ ('# scrolling_div'). ScrollTop ($ ('# scrolling_div'). ScrollTop () + $ ('# element_within_div'). Position (). Top ().
Will
3
Berhati-hatilah bahwa permintaan myElement.offsetTopakan memicu reflow (tata letak meronta-ronta) yang bisa menjadi hambatan kinerja
Kestutis
27
Ingatlah untuk mengatur orangtua bergulir dengan css: position: relativejika tidak, Anda akan menghabiskan banyak waktu debugging seperti yang baru saja saya lakukan.
Savedario
2
Saya harus mengatur overflow-yproperti ke scrolluntuk elemen induk ( scrolling_div), kalau tidak itu tidak berfungsi. Nilai css default untuk overflowproperti adalah autodan meskipun itu juga memungkinkan pengguliran manual, kode js tidak akan berfungsi (bahkan dengan {psition: relative}..)
Evgenia Manolova
2
Masih berfungsi di 2017. Info tambahan: .offsetTop mungkin kembali 0. Maka Anda harus merujuk ke elemen induk dan coba lagi. Aku melakukan itu untuk tag h4maka divkemudian articletag dan hanya articlebekerja untuk saya.
Fenio
66

Anda harus menemukan posisi elemen dalam DIV yang ingin Anda gulir, dan mengatur properti scrollTop.

divElem.scrollTop = 0;

Perbarui :

Kode sampel untuk bergerak ke atas atau ke bawah

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

  function move_down() {
    document.getElementById('divElem').scrollTop -= 10;
  }
Glennular
sumber
3
saya ingin melihatnya gulir, untuk melihatnya tidak menggulir dengan nilai tertentu
Amr Elgarhy
39

Metode 1 - Menggulir halus ke elemen di dalam elemen

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>

Metode 2 - Menggunakan Element.scrollIntoView :

Perhatikan bahwa dukungan browser tidak bagus untuk yang ini

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>

Metode 3 - Menggunakan perilaku gulir 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>

vsync
sumber
1
Perhatikan bahwa perilaku gulir tidak didukung di IE / Edge / Safari
sheats
1
@sheats - katanya persis di tautan dokumentasi MDN yang saya tempatkan di ukuran font yang besar. Bahkan jika itu tidak bekerja untuk browser tersebut, itu tidak berarti Anda tidak boleh menggunakannya. Tidak ada "aturan" semuanya harus berperilaku sama di semua browser. Jika browser modern dapat melakukan sihir, biarkan mereka melakukan sihir.
vsync
Posting ini adalah tentang menggulir seluruh dokumen daripada elemen yang dapat digulir.
@ DoMiNeLa10 - Itu asumsi. OP mungkin memberikan contoh sewenang-wenang yang dimaksudkan untuk menggambarkan masalahnya. Juga, OP bukan perhatian utama melainkan orang-orang yang datang dari mesin pencari mencari solusi yang sehat, dan kemungkinan besar menjawab secara spesifik untuk kebutuhan OP tidak akan membantu mereka, dan tujuan dari situs web ini adalah untuk menciptakan jawaban yang solid yang dapat membantu sebanyak mungkin mungkin. Jawaban saya menyediakan keduanya .
vsync
12

Untuk menggulir elemen ke tampilan div, hanya jika diperlukan, Anda dapat menggunakan scrollIfNeededfungsi ini :

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>

Mpen
sumber
1
Ini sangat membantu. Saya sedikit kesulitan karena saya melewatkan posisi: relatif pada wadah. Itu sangat penting!
brohr
11

Kode harus:

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

Anda ingin menggulir perbedaan antara posisi teratas anak dan posisi teratas div.

Dapatkan akses ke elemen anak menggunakan:

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

dan seterusnya....

pgp
sumber
1
Bukankah seharusnya baris kedua membaca var chElem = document.getElementById('element_within_div');dan baris ketiga membaca var topPos = divElem.offsetTop;?
jayp
7

Jika Anda menggunakan jQuery, Anda dapat menggulir dengan animasi menggunakan yang berikut ini:

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

Animasi ini opsional: Anda juga bisa mengambil nilai scrollTop yang dihitung di atas dan meletakkannya langsung di properti scrollTop wadah .

dlauzon
sumber
5

Native JS, Cross Browser, Smooth Scroll (Pembaruan 2020)

Pengaturan ScrollTopmemang memberikan hasil yang diinginkan tetapi gulir sangat tiba-tiba. Menggunakan jqueryuntuk memiliki scroll yang lancar bukanlah suatu pilihan. Jadi, inilah cara asli untuk menyelesaikan pekerjaan yang mendukung semua browser utama. Referensi - 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'});

Itu dia!


Dan inilah cuplikan kerja untuk yang ragu -

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>

Pembaruan: Seperti yang dapat Anda rasakan di komentar, tampaknya itu Element.scrollTo()tidak didukung di IE11. Jadi jika Anda tidak peduli tentang IE11 (Anda benar-benar tidak boleh), jangan ragu untuk menggunakan ini di semua proyek Anda. Perhatikan bahwa ada dukungan untuk Edge! Jadi Anda tidak benar-benar meninggalkan pengguna Edge / Windows Anda;)

Referensi

Niket Pathak
sumber
1
scrollTo()mungkin didukung di semua browser utama untuk Windowobjek tetapi tidak didukung di IE atau Edge untuk elemen.
Tim Down
Menurut caniuse , didukung di IE11 dan Edge. Belum diuji secara pribadi di peramban ini, tetapi tampaknya didukung.
Niket Pathak
1
Itu window.scrollTo, tidak Element.scrollTo. Coba ini di Edge, misalnya, dan periksa konsol: codepen.io/timdown/pen/abzVEMB
Tim Down
kamu benar. IE11 tidak didukung. Namun Edge v76 (ref) dan di atasnya tampaknya didukung
Niket Pathak
2

Ada dua fakta:

1) Komponen scrollIntoView tidak didukung oleh safari.

2) JS framework jQuery dapat melakukan pekerjaan seperti ini:

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

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

Berikut ini adalah solusi JavaScript murni sederhana yang berfungsi untuk Nomor target (nilai untuk scrollTop), elemen DOM target, atau beberapa kasus String khusus:

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

Dan berikut ini beberapa contoh penggunaannya:

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

atau

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

atau

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

Contoh lain menggunakan jQuery dan menghidupkan.

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");
    }
});
Calon
sumber
0

Pengguliran Animasi Pengguna

Berikut ini adalah contoh cara menggulir secara pemrograman secara <div>horizontal, tanpa JQuery . Untuk menggulir secara vertikal, Anda akan mengganti menulis scrollLeftdengan JavaScript dengan scrollTop.

JSFiddle

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

Kredit untuk Dux .


Pengguliran Animasi Otomatis

Selain itu, berikut adalah fungsi untuk menggulir <div>sepenuhnya ke kiri dan kanan. Satu-satunya hal yang kami ubah di sini adalah kami melakukan pemeriksaan untuk melihat apakah ekstensi penuh dari gulir telah digunakan sebelum melakukan panggilan rekursif untuk menggulir lagi.

JSFiddle

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);
    }
}
Mapsy
sumber
0

Inilah yang akhirnya membantu saya

/** 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);
}
Iñigo Panera
sumber
0

Browser tidak menggulir secara otomatis ke elemen yang mendapat fokus, jadi apa yang Anda juga dapat melakukannya untuk membungkus elemen yang Anda perlu digulir ke dalam <a>...</a>dan kemudian ketika Anda perlu gulir hanya mengatur fokus pada itua

Trident D'Gao
sumber
0

Setelah memilih elemen, cukup gunakan scrollIntoViewfungsi dengan opsi di bawah ini:

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

Jadi jawaban untuk posting ini adalah:

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

mengingat Anda memiliki elemen div yang perlu Anda gulir ke dalam, coba bagian kode ini

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

ini bekerja dengan saya di dalam div dengan sebuah gulir, ini akan bekerja dengan Anda jika Anda mengarahkan mouse ke elemen ini dan kemudian mencoba untuk menggulir ke bawah atau ke atas. Jika itu bekerja secara manual, itu harus bekerja juga

Amado Saladino
sumber