ScrollIntoView () ทำให้ทั้งหน้าเลื่อน


110

ฉันใช้ ScrollIntoView () เพื่อเลื่อนรายการที่ไฮไลต์ในรายการเพื่อดู เมื่อฉันเลื่อนลงไปด้านล่าง ScrollIntoView (false) จะทำงานได้อย่างสมบูรณ์ แต่เมื่อฉันเลื่อนขึ้นไป ScrollIntoView (จริง) ทำให้ทั้งหน้าขยับเล็กน้อยซึ่งฉันคิดว่าตั้งใจ มีวิธีหลีกเลี่ยงการย้ายทั้งหน้าเมื่อใช้ ScrollIntoView (จริง) หรือไม่?

นี่คือโครงสร้างของหน้าของฉัน -

#listOfDivs {
  position:fixed;
  top:100px;
  width: 300px;
  height: 300px;
  overflow-y: scroll;
}

<div="container">
    <div="content"> 
         <div id="listOfDivs"> 
             <div id="item1"> </div>
             <div id="item2"> </div>
             <div id="itemn"> </div>
         </div>
    </div>
</div>

listOfDivs มาจาก ajax call ใช้ซาฟารีมือถือ

ขอบคุณสำหรับความช่วยเหลือล่วงหน้า!


1
คุณสามารถให้ JSFiddle เพื่อให้เราเห็นว่าปัญหาคืออะไร?
Robert Koritnik

คำตอบ:


120

คุณสามารถใช้scrollTopแทนscrollIntoView():

var target = document.getElementById("target");
target.parentNode.scrollTop = target.offsetTop;

jsFiddle: http://jsfiddle.net/LEqjm/

หากมีองค์ประกอบที่เลื่อนได้มากกว่าหนึ่งรายการที่คุณต้องการเลื่อนคุณจะต้องเปลี่ยนองค์ประกอบscrollTopทีละรายการโดยพิจารณาoffsetTopจากองค์ประกอบที่เข้ามาแทรกแซง สิ่งนี้จะช่วยให้คุณสามารถควบคุมได้ละเอียดเพื่อหลีกเลี่ยงปัญหาที่คุณพบ

แก้ไข: offsetTop ไม่จำเป็นต้องสัมพันธ์กับองค์ประกอบหลัก - มันสัมพันธ์กับบรรพบุรุษที่อยู่ในตำแหน่งแรก หากองค์ประกอบหลักไม่อยู่ในตำแหน่ง (สัมพัทธ์สัมบูรณ์หรือคงที่) คุณอาจต้องเปลี่ยนบรรทัดที่สองเป็น:

target.parentNode.scrollTop = target.offsetTop - target.parentNode.offsetTop;

4
FYI จะใช้งานได้เฉพาะเมื่อผู้ปกครองอยู่ที่ด้านบนสุดของหน้า คุณน่าจะทำได้target.parentNode.scrollTop = target.offsetTop - target.parentNode.offsetTop
Phil

2
offsetTop สัมพันธ์กับพาเรนต์ที่อยู่ใกล้ที่สุดดังนั้นหากโหนดพาเรนต์มีposition: relativeคุณไม่ควรลบออฟเซ็ต แต่คุณถูกต้องสำหรับกรณีส่วนใหญ่
Brilliand

2
นี่คือซอ js: jsfiddle.net/LEqjm/258ที่แสดงพฤติกรรมที่ไม่เหมาะสมของ ScrollIntoView
Rafi

1
@Brilliand ขอบคุณสำหรับความคิดเกี่ยวposition: relativeกับ prent div: มันแก้ไขปัญหาได้จริงๆ
Alex Zhukovskiy

มันทำงานบน chrome แต่จะเลื่อนขึ้นเล็กน้อยบน IE ซึ่งจะซ่อนเนื้อหาข้อความจากด้านบน วิธีแก้ปัญหาใด ๆ @Phil ขอบคุณล่วงหน้า
Soniya

128

แก้ไขด้วย:

element.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'start' })

ดู: https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView


1
ขอบคุณที่ใช้งานได้ ฉันไม่เข้าใจการใช้บล็อกและค่าของมันเมื่อฉันอ่าน ตอนนี้มันแก้ปัญหาได้แล้วฉันรู้แล้วว่ากำลังทำอะไรอยู่
Pavan

3
"ใกล้ที่สุด" หมายความว่าอย่างไร แก้ไข: พบคำตอบที่นี่: stackoverflow.com/a/48635751/628418
Sammi

วิธีนี้ช่วยแก้ปัญหาของฉันได้ ฉันเคยเห็นสิ่งนี้เกิดขึ้นในเว็บแอปของเรามาระยะหนึ่งแล้ว แต่มันยากที่จะปิดกั้นการทำซ้ำ หลังจากเพิ่มคุณสมบัติใหม่มันเกิดขึ้นทุกครั้งและฉันสามารถติดตามมันไปยังการโทรนี้ซึ่งไม่มีblock : 'nearest'พารามิเตอร์
roskelld

หากเพียงพวกเขากำหนดความหมายของค่าบล็อก .... เริ่มต้นและใกล้ที่สุด ... เป็นการลองผิดลองถูกทั้งหมด
แบ้

ใช้งานได้กับ Chrome แต่ใช้กับ Edge ไม่ได้สำหรับฉัน
Michael

13
var el = document.querySelector("yourElement");
window.scroll({top: el.offsetTop, behavior: 'smooth'});

หรือจะใช้top: el['offsetTop']
Junior Mayhé

วิธีนี้ได้ผลดีที่สุดสำหรับฉัน แต่ยังมีข้อบกพร่องเล็กน้อยใน firefox - บางครั้งมันก็หยุดบางส่วนไปยังองค์ประกอบ ขอบและโครเมี่ยมดี
ทำเครื่องหมาย

10

ฉันก็มีปัญหานี้เช่นกันและใช้เวลาหลายชั่วโมงในการพยายามจัดการกับมัน ฉันหวังว่าการแก้ปัญหาของฉันอาจช่วยบางคนได้

การแก้ไขของฉันกลายเป็น:

  • สำหรับ Chrome: เปลี่ยน.scrollIntoView()เป็น.scrollIntoView({block: 'nearest'})(ขอบคุณ @jfrohn)
  • สำหรับ Firefox: ใช้overflow: -moz-hidden-unscrollable;กับองค์ประกอบคอนเทนเนอร์ที่เปลี่ยนไป
  • ไม่ผ่านการทดสอบในเบราว์เซอร์อื่น

9

เล่นกับscrollIntoViewIfNeeded()... ตรวจสอบให้แน่ใจว่าเบราว์เซอร์รองรับ


1
ไม่ทราบว่าเป็นสิ่ง มีpolyfill
mpen

ในเอกสารระบุว่าไม่ได้มาตรฐาน แต่ใช้งานได้ดี เราควรใช้ไหม
Shyam Kumar

8

ฉันได้เพิ่มวิธีการแสดงพฤติกรรมที่ไม่เหมาะสมของ ScrollIntoView - http://jsfiddle.net/LEqjm/258/ [ควรเป็นความคิดเห็น แต่ฉันไม่มีชื่อเสียงเพียงพอ]

$("ul").click(function() {
    var target = document.getElementById("target");
if ($('#scrollTop').attr('checked')) {
    target.parentNode.scrollTop = target.offsetTop;    
} else {
        target.scrollIntoView(!0);
}
});

7
ไม่ใช่คำถาม jQuery
ที่นั่ง

6

ปลั๊กอิน jQuery scrollintoview()เพิ่มความสามารถในการใช้งาน

แทนที่จะใช้ DOM เริ่มต้นคุณสามารถใช้ปลั๊กอินที่ทำให้เคลื่อนไหวเคลื่อนไหวได้และไม่มีเอฟเฟกต์ที่ไม่ต้องการ นี่เป็นวิธีที่ง่ายที่สุดในการใช้งานโดยใช้ค่าเริ่มต้น:

$("yourTargetLiSelector").scrollintoview();

ตรงไปที่โพสต์บล็อกนี้ซึ่งคุณสามารถอ่านรายละเอียดทั้งหมดและในที่สุดก็จะพาคุณไปที่ซอร์สโค้ดของปลั๊กอินGitHub

ปลั๊กอินนี้ค้นหาองค์ประกอบบรรพบุรุษที่เลื่อนได้ที่ใกล้ที่สุดโดยอัตโนมัติและเลื่อนเพื่อให้องค์ประกอบที่เลือกอยู่ภายในพอร์ตมุมมองที่มองเห็นได้ หากองค์ประกอบอยู่ในพอร์ตมุมมองแล้วจะไม่ทำอะไรแน่นอน


19
@ Brilliand: แน่นอนว่าเป็นความจริง แต่นั่นไม่ได้หมายความว่าพวกเขาไม่ได้ใช้มันหรือไม่เต็มใจที่จะใช้มัน สิ่งที่ฉันทำคือให้ทางเลือก ขึ้นอยู่กับ OP เพื่อตัดสินใจว่านั่นคือเส้นทางที่พวกเขาต้องการหรือไม่ บางทีพวกเขาไม่เคยพิจารณาใช้ jQuery ตั้งแต่แรก
Robert Koritnik

OP นั้นไม่ได้กล่าวถึง jQuery โดยเฉพาะว่าไม่เกี่ยวข้องอย่างยิ่ง: คำตอบของ @ RobertKoritnik ให้บริการฉันอย่างสมบูรณ์แบบ
Dave Land

1
อนึ่ง Bing กำลังแสดงตัวอย่างโค้ดของคุณในผลการค้นหาสำหรับ "ป้องกันไม่ให้องค์ประกอบของบรรพบุรุษเลื่อนด้วย scrollintoview" :-)
Dave Land

2

การใช้แนวคิดของ Brilliant นี่คือวิธีแก้ปัญหาที่เลื่อน (แนวตั้ง) เท่านั้นหากไม่สามารถมองเห็นองค์ประกอบได้ในขณะนี้ แนวคิดคือการรับกล่องขอบเขตของวิวพอร์ตและองค์ประกอบที่จะแสดงในพื้นที่พิกัดหน้าต่างเบราว์เซอร์ ตรวจสอบว่าสามารถมองเห็นได้หรือไม่หากไม่ให้เลื่อนตามระยะที่ต้องการเพื่อให้องค์ประกอบแสดงที่ด้านบนหรือด้านล่างของวิวพอร์ต

    function ensure_visible(element_id)
    {
        // adjust these two to match your HTML hierarchy
        var element_to_show  = document.getElementById(element_id);
        var scrolling_parent = element_to_show.parentElement;

        var top = parseInt(scrolling_parent.getBoundingClientRect().top);
        var bot = parseInt(scrolling_parent.getBoundingClientRect().bottom);

        var now_top = parseInt(element_to_show.getBoundingClientRect().top);
        var now_bot = parseInt(element_to_show.getBoundingClientRect().bottom);

        // console.log("Element: "+now_top+";"+(now_bot)+" Viewport:"+top+";"+(bot) );

        var scroll_by = 0;
        if(now_top < top)
            scroll_by = -(top - now_top);
        else if(now_bot > bot)
            scroll_by = now_bot - bot;
        if(scroll_by != 0)
        {
            scrolling_parent.scrollTop += scroll_by; // tr.offsetTop;
        }
    }

2

กำลังเพิ่มข้อมูลเพิ่มเติมเพื่อ@Jescoโพสต์

  • Element.scrollIntoViewIfNeeded() non-standard WebKit methodสำหรับเบราว์เซอร์ Chrome, Opera, Safari ถ้าองค์ประกอบที่มีอยู่แล้วภายในพื้นที่ที่มองเห็นของหน้าต่างเบราว์เซอร์แล้วไม่มีการเลื่อนจะเกิดขึ้น
  • Element.scrollIntoView() วิธีการเลื่อนองค์ประกอบที่เรียกเข้าไปในพื้นที่ที่มองเห็นได้ของหน้าต่างเบราว์เซอร์

ลองใช้รหัสด้านล่างในmozilla.org scrollIntoView()ลิงค์ โพสต์เพื่อระบุเบราว์เซอร์

var xpath = '//*[@id="Notes"]';
ScrollToElement(xpath);

function ScrollToElement(xpath) {
    var ele = $x(xpath)[0];
    console.log( ele );

    var isChrome = !!window.chrome && (!!window.chrome.webstore || !!window.chrome.runtime);
    if (isChrome) { // Chrome
        ele.scrollIntoViewIfNeeded();
    } else {
        var inlineCenter = { behavior: 'smooth', block: 'center', inline: 'start' };
        ele.scrollIntoView(inlineCenter);
    }
}

2

ในบริบทของฉันเขาจะดันแถบเครื่องมือเหนียวออกจากหน้าจอหรือป้อนถัดจากปุ่ม fab ด้วยค่าสัมบูรณ์

โดยใช้การแก้ไขที่ใกล้ที่สุด

const element = this.element.nativeElement;
const table = element.querySelector('.table-container');
table.scrollIntoView({
  behavior: 'smooth', block: 'nearest'
});

1

ฉันมีปัญหาเดียวกันฉันแก้ไขโดยลบtransform:translateYCSS ที่ฉันวางไว้บนfooterหน้า

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.