ฉันจะอัปเดต window.location.hash โดยไม่ต้องกระโดดเอกสารได้อย่างไร


163

ฉันมีแผงเลื่อนบนเว็บไซต์ของฉัน

เมื่อการเคลื่อนไหวเสร็จสิ้นฉันจะตั้งค่าแฮชเป็นอย่างนั้น

function() {
   window.location.hash = id;
}

(นี่คือการติดต่อกลับและidได้รับมอบหมายก่อนหน้านี้)

วิธีนี้ใช้งานได้ดีเพื่อให้ผู้ใช้สามารถคั่นหน้าพาเนลและสำหรับเวอร์ชันที่ไม่ใช่ JavaScript ให้ทำงานได้

อย่างไรก็ตามเมื่อฉันอัปเดตแฮชเบราว์เซอร์จะข้ามไปยังตำแหน่ง ฉันคิดว่านี่เป็นพฤติกรรมที่คาดหวัง

คำถามของฉันคือ: ฉันจะป้องกันได้อย่างไร คือฉันจะเปลี่ยนแฮชของหน้าต่างได้อย่างไร แต่ไม่มีเบราว์เซอร์เลื่อนไปที่องค์ประกอบหากมีแฮชอยู่? บางสิ่งบางอย่างevent.preventDefault()?

ฉันใช้ jQuery 1.4 และปลั๊กอิน scrollTo

ขอบคุณมาก!

ปรับปรุง

นี่คือรหัสที่เปลี่ยนพาเนล

$('#something a').click(function(event) {
    event.preventDefault();
    var link = $(this);
    var id = link[0].hash;

    $('#slider').scrollTo(id, 800, {
        onAfter: function() {

            link.parents('li').siblings().removeClass('active');
            link.parent().addClass('active');
            window.location.hash = id;

            }
    });
});

2
ฉันถือว่าคุณได้ลองแล้วevent.preventDefault():)
Marko

@ Marko ฉันไม่รู้จะวางที่ไหน!
alex

คุณสามารถโพสต์ส่วนที่เหลือของรหัสของคุณ?
Marko

@ Marko Ivanovski ฉันไม่คิดว่ามันเกี่ยวข้อง แต่ฉันจะเห็นสิ่งที่ฉันสามารถทำได้
alex

3
@ กาเร็ ธ ฉันไม่คิดว่าจะมีที่สำหรับมันเพราะมันเกิดขึ้นทันทีที่ฉันอัพเดตแฮช
alex

คำตอบ:


261

มีวิธีแก้ปัญหาโดยใช้ประวัติ API บนเบราว์เซอร์สมัยใหม่ที่มีทางเลือกย้อนหลัง

if(history.pushState) {
    history.pushState(null, null, '#myhash');
}
else {
    location.hash = '#myhash';
}

เครดิตไปที่Lea Verou


นี่คือคำตอบที่ดีกว่าในความคิดของฉัน
เกร็ก Annandale

10
โปรดทราบว่า pushState มีผลข้างเคียง (เยื้อง) ของการเพิ่มสถานะลงในสแต็กประวัติเบราว์เซอร์ กล่าวอีกนัยหนึ่งเมื่อผู้ใช้คลิกปุ่มย้อนกลับจะไม่มีอะไรเกิดขึ้นนอกจากคุณจะเพิ่มผู้ฟังเหตุการณ์ป๊อบสเตท
David Cook

32
@DavidCook - เราสามารถใช้history.replaceState(ซึ่งสำหรับการเปลี่ยนแปลงแฮชอาจทำให้เข้าใจได้มากกว่า) เพื่อหลีกเลี่ยงความต้องการpopstateผู้ฟังเหตุการณ์
แจ็ค

สิ่งนี้ใช้ได้สำหรับฉัน ฉันชอบผลของการเปลี่ยนแปลงทางประวัติศาสตร์ ฉันต้องการเพิ่มข้อแม้ที่จะไม่ทำให้เกิดhashchangeเหตุการณ์ นั่นคือสิ่งที่ฉันต้องแก้ไข
Jordan

คำเตือน! สิ่งนี้จะไม่ทำให้เกิดhashchangeเหตุการณ์
santiago arizti

52

ปัญหาคือคุณกำลังตั้งค่าwindow.location.hashเป็นแอตทริบิวต์ ID ขององค์ประกอบ มันเป็นพฤติกรรมที่คาดหวังสำหรับเบราว์เซอร์ที่จะข้ามไปยังองค์ประกอบนั้นไม่ว่าคุณจะ "PreventDefault ()" หรือไม่ก็ตาม

วิธีหนึ่งที่จะหลีกเลี่ยงปัญหานี้ได้คือนำหน้าแฮชที่มีค่าตามต้องการดังนี้:

window.location.hash = 'panel-' + id.replace('#', '');

จากนั้นสิ่งที่คุณต้องทำคือการตรวจสอบแฮชนำหน้าในการโหลดหน้า เป็นโบนัสที่เพิ่มเข้ามาคุณสามารถเลื่อนดูได้อย่างนุ่มนวลเนื่องจากตอนนี้คุณสามารถควบคุมค่าแฮช ...

$(function(){
    var h = window.location.hash.replace('panel-', '');
    if (h) {
        $('#slider').scrollTo(h, 800);
    }
});

หากคุณต้องการให้สิ่งนี้ทำงานตลอดเวลา (และไม่ใช่แค่การโหลดหน้าเริ่มต้น) คุณสามารถใช้ฟังก์ชันเพื่อตรวจสอบการเปลี่ยนแปลงค่าแฮชและข้ามไปยังองค์ประกอบที่ถูกต้องได้ทันที:

var foundHash;
setInterval(function() {
    var h = window.location.hash.replace('panel-', '');
    if (h && h !== foundHash) {
        $('#slider').scrollTo(h, 800);
        foundHash = h;
    }
}, 100);

2
นี่เป็นทางออกเดียวที่ตอบคำถามได้จริงโดยไม่ต้องกระโดด
amosmos

นี่เป็นการตอบคำถามที่อธิบายถึงการเพิ่มและการลบค่าตามอำเภอใจสำหรับแฮชเพื่อหลีกเลี่ยงการกระโดดตามพฤติกรรมของเบราว์เซอร์เริ่มต้น
lowtechsun

1
ทางออกที่ดี แต่ทำให้ OPs อ่อนตัวลงเนื่องจากไม่เห็นด้วยกับการใช้ส่วนที่คั่นไว้
Samus

27

วิธีแก้ปัญหาราคาถูกและน่ารังเกียจ .. ใช้ # น่าเกลียด! สไตล์

วิธีตั้งค่า:

window.location.hash = '#!' + id;

หากต้องการอ่าน:

id = window.location.hash.replace(/^#!/, '');

เนื่องจากมันไม่ตรงและยึดเหนี่ยวหรือรหัสในหน้ามันจึงไม่กระโดด


3
ฉันต้องรักษาความเข้ากันได้กับ IE 7 และเว็บไซต์มือถือบางรุ่น วิธีนี้สะอาดที่สุดสำหรับฉัน โดยทั่วไปฉันจะอยู่เหนือโซลูชั่น pushState ทุกครั้ง
Eric Goodwin

1
การตั้งค่าแฮชด้วย: window.location.hash = '#/' + id;แล้วแทนที่ด้วย: window.location.hash.replace(/^#\//, '#');จะใส่ url เป็นบิต -> projects/#/tab1
braitsch

13

ทำไมคุณถึงไม่ได้ตำแหน่งการเลื่อนปัจจุบันวางไว้ในตัวแปรจากนั้นกำหนดแฮชและวางการเลื่อนหน้ากลับไปยังตำแหน่งเดิม:

var yScroll=document.body.scrollTop;
window.location.hash = id;
document.body.scrollTop=yScroll;

สิ่งนี้น่าจะใช้ได้


1
หืมนี่มันใช้งานได้สำหรับฉันซักพัก แต่ในช่วงไม่กี่เดือนที่ผ่านมาสิ่งนี้หยุดทำงานกับ firefox ....
matchew

10

ฉันใช้การผสมผสานของโซลูชั่น Attila Fulop (Lea Verou) สำหรับเบราว์เซอร์ที่ทันสมัยและโซลูชั่น Gavin Brock สำหรับเบราว์เซอร์รุ่นเก่าดังนี้:

if (history.pushState) {
    // IE10, Firefox, Chrome, etc.
    window.history.pushState(null, null, '#' + id);
} else {
    // IE9, IE8, etc
    window.location.hash = '#!' + id;
}

ดังที่กาวินบร็อคจับภาพกลับมาคุณจะต้องปฏิบัติกับสายอักขระ (ซึ่งในกรณีนี้สามารถมีหรือไม่ "!") ดังนี้:

id = window.location.hash.replace(/^#!?/, '');

ก่อนหน้านั้นฉันลองวิธีแก้ปัญหาคล้ายกับที่เสนอโดยผู้ใช้ 706270 แต่มันใช้งานไม่ได้กับ Internet Explorer: เนื่องจากเครื่องมือ Javascript ของมันไม่เร็วมากคุณสามารถสังเกตเห็นการเพิ่มขึ้นและลดลงของสกรอลล์


2

วิธีนี้ใช้ได้ผลสำหรับฉัน

ปัญหาเกี่ยวกับการตั้งค่าlocation.hashคือหน้าจะข้ามไปยัง id นั้นหากพบในหน้านั้น

ปัญหาwindow.history.pushStateคือมันเพิ่มรายการในประวัติสำหรับแต่ละแท็บที่ผู้ใช้คลิก จากนั้นเมื่อผู้ใช้คลิกbackปุ่มพวกเขาไปที่แท็บก่อนหน้า (นี่อาจเป็นหรือไม่ใช่สิ่งที่คุณต้องการมันไม่ใช่สิ่งที่ฉันต้องการ)

สำหรับฉันแล้วreplaceStateตัวเลือกที่ดีกว่าคือการแทนที่ประวัติปัจจุบันเท่านั้นดังนั้นเมื่อผู้ใช้คลิกbackปุ่มพวกเขาจะไปที่หน้าก่อนหน้า

$('#tab-selector').tabs({
  activate: function(e, ui) {
    window.history.replaceState(null, null, ui.newPanel.selector);
  }
});

ตรวจสอบเอกสาร API ประวัติของ MDN


1

ฉันไม่แน่ใจว่าคุณสามารถเปลี่ยนองค์ประกอบเดิม แต่เปลี่ยนจากการใช้ id attr เป็นอย่างอื่นเช่น data-id ได้อย่างไร จากนั้นแค่อ่านค่า data-id สำหรับค่าแฮชของคุณและมันจะไม่กระโดด


1

วิธีนี้ใช้ได้ผลสำหรับฉัน

// store the currently selected tab in the hash value
    if(history.pushState) {
        window.history.pushState(null, null, '#' + id);
    }
    else {
        window.location.hash = id;
    }

// on load of the page: switch to the currently selected tab
var hash = window.location.hash;
$('#myTab a[href="' + hash + '"]').tab('show');

และรหัส js เต็มของฉันคือ

$('#myTab a').click(function(e) {
  e.preventDefault();
  $(this).tab('show');
});

// store the currently selected tab in the hash value
$("ul.nav-tabs > li > a").on("shown.bs.tab", function(e) {
  var id = $(e.target).attr("href").substr(1);
    if(history.pushState) {
        window.history.pushState(null, null, '#' + id);
    }
    else {
        window.location.hash = id;
    }
   // window.location.hash = '#!' + id;
});

// on load of the page: switch to the currently selected tab
var hash = window.location.hash;
// console.log(hash);
$('#myTab a[href="' + hash + '"]').tab('show');

0

เมื่อใช้เฟรมเวิร์ก laravel ฉันมีปัญหาบางอย่างกับการใช้ฟังก์ชัน route-> back () เนื่องจากลบแฮชของฉัน เพื่อรักษาแฮชของฉันฉันสร้างฟังก์ชั่นง่าย ๆ :

$(function() {   
    if (localStorage.getItem("hash")    ){
     location.hash = localStorage.getItem("hash");
    }
}); 

และฉันตั้งไว้ในฟังก์ชั่น JS อื่น ๆ ของฉันเช่นนี้:

localStorage.setItem("hash", myvalue);

คุณสามารถตั้งชื่อค่าที่เก็บข้อมูลในพื้นที่ของคุณได้ตามต้องการ hashเหมืองชื่อ

ดังนั้นหากตั้งแฮชไว้ที่หน้า 1 แล้วคุณไปที่หน้า 2; แฮชจะถูกสร้างขึ้นใหม่ในหน้า 1 เมื่อคุณคลิกย้อนกลับบนหน้า 2

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