history.replaceState () ตัวอย่าง?


127

มีใครให้ตัวอย่างการทำงานสำหรับ history.replaceState ได้ไหม นี่คือสิ่งที่w3.orgกล่าวว่า:

history . replaceState(data, title [, url ] )

อัปเดตรายการปัจจุบันในประวัติเซสชันเพื่อให้มีข้อมูลชื่อเรื่องและหากระบุไว้และไม่เป็นค่าว่าง URL

ปรับปรุง:

สิ่งนี้ทำงานได้อย่างสมบูรณ์:

history.replaceState( {} , 'foo', '/foo' );

URL กำลังเปลี่ยน แต่ชื่อไม่เปลี่ยน นั่นเป็นข้อบกพร่องหรือฉันทำอะไรหายไป? ทดสอบกับ Chrome รุ่นล่าสุด


3
โดยทั่วไปฉันจะไม่ผลักดันไลบรารีส่วนเสริมสำหรับคำถามเกี่ยวกับ JavaScript แต่ในกรณีนี้ฉันจะยกเว้น History.jsห้องสมุดเป็น Shim ขนาดเล็กที่ทำความสะอาดมากขึ้นของความซุกซนที่แปลกประหลาดใน API ประวัติเบราว์เซอร์ที่ทันสมัย มันยังให้การสนับสนุนเพิ่มเติมสำหรับ IE เวอร์ชันเก่า
Pointy

2
MDN มีบทความที่ดีเกี่ยวกับการจัดการประวัติเบราว์เซอร์
sachleen

@Pointy history.js ใช้งานได้ดี ฉันได้อัปเดตรหัสในคำถามของฉันแล้ว ไม่มีปัญหาของฉันคือฉันไม่สามารถกลับไปที่หน้าก่อนหน้าด้วยปุ่มย้อนกลับของเบราว์เซอร์
Serjas

3
ตามMozillaที่titleพารามิเตอร์ไม่ได้ใช้จริง
Rocket Hazmat

3
คำตอบแรกไม่ควรเป็นคำตอบที่ยอมรับได้จริง ๆ เนื่องจากคำถามขอreplaceStateตัวอย่างและคำตอบที่ยอมรับนั้นไม่มีreplaceStateตัวอย่าง
CorayThan

คำตอบ:


68

อันที่จริงนี่เป็นข้อผิดพลาดแม้ว่าจะตั้งใจมา 2 ปีแล้วก็ตาม ปัญหาอยู่ที่ข้อกำหนดที่ไม่ชัดเจนและความซับซ้อนเมื่อdocument.titleและย้อนกลับ / ไปข้างหน้าเกี่ยวข้อง

ดูข้อผิดพลาดในการอ้างอิงWebkitและMozilla นอกจากนี้ Opera ในการเปิดตัว History API กล่าวว่ามันไม่ได้ใช้พารามิเตอร์ titleและอาจจะยังใช้ไม่ได้

ปัจจุบันอาร์กิวเมนต์ที่ 2 ของ pushState และ replaceState ซึ่งเป็นชื่อของรายการประวัติ - ไม่ได้ใช้ในการใช้งานของ Opera แต่อาจใช้เวลาหนึ่งวัน

ทางออกที่เป็นไปได้

วิธีเดียวที่ฉันเห็นคือเปลี่ยนองค์ประกอบชื่อเรื่องและใช้ pushState แทน:

document.getElementsByTagName('title')[0].innerHTML = 'bar';
window.history.pushState( {} , 'bar', '/bar' );

สำหรับผู้ใช้ jquery .. ให้ลอง $ ("title"). html (_title);
suraj jain

3
ซึ่งอาจส่งผลให้ผู้ใช้จำเป็นต้อง "ดับเบิลคลิก" ที่ปุ่มย้อนกลับขึ้นอยู่กับว่าคุณใช้สิ่งนี้อย่างไร วิธีแก้ปัญหาที่ง่ายกว่านั้นคือใช้ต่อไปreplaceState()และตั้งชื่อเอกสารด้วยตนเองdocument.title = "title"
newshorts

38

นี่คือตัวอย่างขั้นต่ำที่สร้างขึ้น

console.log( window.location.href );  // whatever your current location href is
window.history.replaceState( {} , 'foo', '/foo' );
console.log( window.location.href );  // oh, hey, it replaced the path with /foo

มีอะไรมากกว่านั้นreplaceState()แต่ฉันไม่รู้ว่าคุณต้องการทำอะไรกันแน่


2
url กำลังเปลี่ยน แต่ชื่อไม่เปลี่ยน .. ทดสอบด้วย chrome ล่าสุด @trott
Serjas

6
@Serjas titleพารามิเตอร์ในreplaceState()คือเพื่อความรู้ที่ดีที่สุดของฉันไม่สนใจในทุกเบราว์เซอร์
Trott

10

history.pushStateผลักสถานะหน้าปัจจุบันไปยังกองประวัติและเปลี่ยน URL ในแถบที่อยู่ ดังนั้นเมื่อคุณย้อนกลับไปสถานะนั้น (วัตถุที่คุณส่งผ่าน) จะกลับมาหาคุณ

ปัจจุบันนั่นคือทั้งหมดที่ทำ การดำเนินการอื่น ๆ ของเพจเช่นการแสดงเพจใหม่หรือการเปลี่ยนชื่อเพจจะต้องดำเนินการโดยคุณ

ข้อมูลจำเพาะ W3C ที่คุณเชื่อมโยงเป็นเพียงแบบร่างและเบราว์เซอร์อาจใช้งานแตกต่าง ตัวอย่างเช่นFirefoxละเว้นtitleพารามิเตอร์อย่างสมบูรณ์

นี่คือตัวอย่างง่ายๆpushStateที่ฉันใช้บนเว็บไซต์ของฉัน

(function($){
    // Use AJAX to load the page, and change the title
    function loadPage(sel, p){
        $(sel).load(p + ' #content', function(){
            document.title = $('#pageData').data('title');
        });
    }

    // When a link is clicked, use AJAX to load that page
    // but use pushState to change the URL bar
    $(document).on('click', 'a', function(e){
        e.preventDefault();
        history.pushState({page: this.href}, '', this.href);
        loadPage('#frontPage', this.href);
    });

    // This event is triggered when you visit a page in the history
    // like when yu push the "back" button
    $(window).on('popstate', function(e){
        loadPage('#frontPage', location.pathname);
        console.log(e.originalEvent.state);
    });
}(jQuery));

29
เหตุใดคำตอบที่ยอมรับจึงอธิบาย "pushState" แทนที่จะเป็น "replaceState"
Giwrgos Tsopanoglou

1
@GiwrgosTsopanoglou: ฉันตอบเมื่อปีที่แล้วดังนั้นฉันไม่แน่ใจว่าทำไม :-P อย่างไรก็ตามreplaceStateเปลี่ยนสถานะของเพจปัจจุบัน ช่วยให้คุณเปลี่ยนออบเจ็กต์สถานะและ URL ของสถานะเพจปัจจุบัน
Rocket Hazmat

2
มันแปลกมากที่ฉันกำลังหาข้อมูลเกี่ยวกับ replaceState และฉันก็อ่านเกี่ยวกับ pushState: P
Giwrgos Tsopanoglou

6

ดูตัวอย่าง

window.history.replaceState({
    foo: 'bar'
}, 'Nice URL Title', '/nice_url');

window.onpopstate = function (e) {
    if (typeof e.state == "object" && e.state.foo == "bar") {
        alert("Blah blah blah");
    }
};

window.history.go(-1);

และค้นหาlocation.hash;


2

อาร์กิวเมนต์ที่สองTitleไม่ได้หมายถึงชื่อของเพจ - เป็นคำจำกัดความ / ข้อมูลสำหรับสถานะของเพจนั้นมากกว่า

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

อ้างอิง: http://spoiledmilk.com/blog/html5-changing-the-browser-url-without-refreshing-page/


2

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

Firefox ไม่สนใจพารามิเตอร์นี้ในขณะนี้แม้ว่าจะใช้ในอนาคตก็ตาม การส่งสตริงว่างตรงนี้ควรปลอดภัยต่อการเปลี่ยนแปลงวิธีการในอนาคต หรือคุณสามารถส่งชื่อสั้น ๆ สำหรับสถานะที่คุณกำลังจะย้าย


อาร์กิวเมนต์ที่สองไม่ได้อ้างถึงชื่อของหน้าเว็บ - เอกสาร MDN ที่คุณเชื่อมโยงระบุว่า"ส่งชื่อสั้น ๆสำหรับสถานะที่คุณกำลังจะย้าย" . นี้เห็นด้วยกับของ W3C อินเตอร์เฟซประวัติศาสตร์เอกสารกล่าวว่า"Pushes ข้อมูลที่กำหนดลงในประวัติศาสตร์เซสชั่นที่มีชื่อได้รับ" ข้อมูลในวลีนั้นคือข้อมูลสถานะดังนั้นอีกครั้งชื่อเรื่องจึงอ้างถึงสถานะ (ข้อมูล)
Stephen P

1

ฉันอยากตอบกลับคำตอบของ @ Sev จริงๆ

Sev ถูกต้องมีข้อผิดพลาดภายในไฟล์ window.history.replaceState

ในการแก้ไขปัญหานี้เพียงแค่เขียนตัวสร้างใหม่เพื่อตั้งชื่อเรื่องด้วยตนเอง

var replaceState_tmp = window.history.replaceState.constructor;
window.history.replaceState.constructor = function(obj, title, url){
    var title_ = document.getElementsByTagName('title')[0];
    if(title_ != undefined){
        title_.innerHTML = title;
    }else{
        var title__ = document.createElement('title');
        title__.innerHTML = title;
        var head_ = document.getElementsByTagName('head')[0];
        if(head_ != undefined){
            head_.appendChild(title__);
        }else{
            var head__ = document.createElement('head');
            document.documentElement.appendChild(head__);
            head__.appendChild(title__);
        }
    }
    replaceState_tmp(obj,title, url);
}

2
อย่าทำอย่างนั้น การเขียนทับฟังก์ชันเริ่มต้นเป็นรูปแบบที่ไม่ดีอย่างยิ่ง
René Roth

3
คุณแนะนำอะไรอีกเมื่อคุณต้องการแก้ไขข้อบกพร่องนี้
Glenn Plas

@GlennPlas เปิด PR ต่อต้านรีโพสต์ :)
zero_cool

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