เปลี่ยน URL ในเบราว์เซอร์โดยไม่โหลดหน้าใหม่โดยใช้ JavaScript


297

ฉันจะมีการดำเนินการJavaScriptที่อาจมีผลกระทบกับหน้าปัจจุบันได้อย่างไร แต่จะเปลี่ยน URL ในเบราว์เซอร์ด้วยดังนั้นหากผู้ใช้กดปุ่มโหลดซ้ำหรือคั่นหน้า URL ใหม่จะถูกใช้

มันก็จะดีถ้าปุ่มย้อนกลับจะโหลด URL เดิม

ฉันพยายามบันทึกสถานะ JavaScript ใน URL


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

1
A "sort-of" ใช้งานได้ดีpushState:for(i=1;i<50;i++){var txt="..................................................";txt=txt.slice(0,i)+"HTML5"+txt.slice(i,txt.length);history.pushState({}, "html5", txt);}
Derek 朕會功夫

ตัวอย่างของเอฟเฟกต์นี้: dujour.com
Ben

2
ตัวอย่างของเอฟเฟกต์นี้: facebook.com (เมื่อเปิดรูปภาพในไลท์บ็อกซ์)

นี่เป็นคำถามที่ดี อย่างไรก็ตามมันเป็นสถานการณ์ที่น่าเศร้าถ้าหากคำถามนี้ได้ถูกถามในลักษณะนี้ในวันนี้มันจะถูกลดระดับลงและเพิ่มขึ้นโดย "นี่ไม่ใช่เว็บไซต์ประเภทที่คุณให้ผู้คนเขียนรหัสทั้งหมดให้คุณ"
dewd

คำตอบ:


118

กับ HTML 5 ใช้ฟังก์ชั่นhistory.pushState ตัวอย่างเช่น:

<script type="text/javascript">
var stateObj = { foo: "bar" };
function change_my_url()
{
   history.pushState(stateObj, "page 2", "bar.html");
}
var link = document.getElementById('click');
link.addEventListener('click', change_my_url, false);
</script>

และ href:

<a href="#" id='click'>Click to change url to bar.html</a>

หากคุณต้องการเปลี่ยน URL โดยไม่ต้องเพิ่มรายการลงในรายการปุ่มย้อนกลับให้ใช้history.replaceStateแทน


คุณพูดถูกครั้งล่าสุดที่ฉันทดลองกับ Chrome ตอนนี้ฉันเพิ่งลองใช้ Firefox 3.6 บน Ubuntu ของฉันมันไม่ทำงาน ฉันเดาว่าเราจะต้องรอจนกว่า HTML5 จะได้รับการสนับสนุนอย่างเต็มที่ใน FF
clu3

15
โค้ดตัวอย่างที่ถูกตัดและวางจากdeveloper.mozilla.org/en/DOM/Manipulating_the_browser_history ซึ่งอันที่จริงแล้วการอธิบายความหมายของ foo และ bar ในกรณีนี้
mikemaccana

2
foo and bar ไม่ได้มีความหมายอะไรเลยมันเป็นวัตถุของรัฐที่กำหนดไว้โดยพลการซึ่งคุณสามารถกลับมาใหม่ได้ในภายหลัง
Paul Dixon

3
@ พอล: ใช่บทความข้างต้นให้ข้อมูลนั้น
mikemaccana

2
ในฐานะที่เป็นของการโพสต์ความคิดเห็นนี้มันทำงานบน firefox chrome และซาฟารี ไม่มีโชคกับซาฟารีมือถือบน ipad หรือ iphone แม้ว่า :(
Sid

187

หากคุณต้องการที่จะทำงานในเบราว์เซอร์ที่ไม่สนับสนุนhistory.pushStateและhistory.popStateยังเป็นวิธีที่ "เก่า" คือการกำหนดตัวบ่งชี้ส่วนซึ่งจะไม่ทำให้เกิดการโหลดหน้า

แนวคิดพื้นฐานคือการตั้งค่าwindow.location.hashคุณสมบัติเป็นค่าที่มีข้อมูลสถานะใดก็ตามที่คุณต้องการจากนั้นใช้เหตุการณ์ window.onhashchangeหรือเบราว์เซอร์รุ่นเก่าที่ไม่รองรับonhashchange(IE <8, Firefox <3.6) ตรวจสอบเป็นระยะ ดูว่าแฮชมีการเปลี่ยนแปลง (โดยใช้setIntervalตัวอย่าง) และปรับปรุงหน้า คุณจะต้องตรวจสอบค่าแฮชในการโหลดหน้าเพื่อตั้งค่าเนื้อหาเริ่มต้น

หากคุณใช้ jQuery จะมีปลั๊กอินแฮชเชนจ์ที่จะใช้วิธีใดก็ได้ที่เบราว์เซอร์รองรับ ฉันแน่ใจว่ามีปลั๊กอินสำหรับห้องสมุดอื่นเช่นกัน

สิ่งหนึ่งที่ต้องระวังคือการชนกับรหัสบนหน้าเว็บเนื่องจากเบราว์เซอร์จะเลื่อนไปยังองค์ประกอบใด ๆ ที่มีรหัสที่ตรงกัน


2
ไม่ต้องเสิร์ชเอ็นจิ้นไม่สนใจลิงค์ภายในเหล่านี้ (แฮช)? ในสถานการณ์ของฉันฉันต้องการไปเดอร์เพื่อรับลิงค์เหล่านี้ด้วย
Drew Noakes

3
@ ดึงเท่าที่ฉันรู้ไม่มีวิธีสำหรับเครื่องมือค้นหาที่จะปฏิบัติต่อส่วนของหน้าเป็นผลแยกต่างหาก
Matthew Crumley

8
ขณะนี้มีข้อเสนอเพื่อให้เครื่องมือค้นหาดูแฮช: googlewebmastercentral.blogspot.com/2009/10/…
LKM

5
แทนที่จะใช้setIntervalเพื่อตรวจสอบเหตุการณ์document.location.hashสามารถใช้งานได้เนื่องจากมีการใช้hashchangeงานมากขึ้น ตรวจสอบที่นี่สำหรับสิ่งที่เบราว์เซอร์สนับสนุนแต่ละมาตรฐาน แนวทางปัจจุบันของฉันคือใช้ push / popState บนเบราว์เซอร์ที่รองรับ ในที่อื่น ๆ ฉันตั้งค่าแฮชและดูเฉพาะhashchangeในเบราว์เซอร์ที่สนับสนุน สิ่งนี้ทำให้ IE <= 7 ไม่มีการสนับสนุนประวัติ แต่ด้วย Permalink ที่มีประโยชน์ แต่ใครจะสนใจ IE <= 7 ประวัติ
Irae Carvalho

2
@gabeDel ใช่ แต่ฉันไม่คิดว่า Analytics บันทึกแฮชดังนั้นมันจะมี URL เดียวกัน วิธีที่ดีกว่าคือการโทรด้วยตนเองด้วย_trackPageviewURL "ของจริง" ของหน้าใหม่
Matthew Crumley

37

window.location.href มี URL ปัจจุบัน คุณสามารถอ่านจากมันคุณสามารถผนวกเข้ากับมันและคุณสามารถแทนที่ซึ่งอาจทำให้เกิดการโหลดหน้าซ้ำ

หากดูเหมือนว่าคุณต้องการบันทึกสถานะจาวาสคริปต์ใน URL เพื่อให้สามารถบุ๊กมาร์กได้โดยไม่ต้องโหลดหน้าใหม่ต่อท้าย URL ปัจจุบันหลังจาก # และมีจาวาสคริปต์ที่ถูกเรียกโดยเหตุการณ์ onload แยกปัจจุบัน URL เพื่อดูว่ามีสถานะที่บันทึกไว้หรือไม่

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


2
การบันทึกสถานะจาวาสคริปต์ใน URL เป็นสิ่งที่ฉันพยายามจะทำ
Steven Noble

21

ฉันสงสัยอย่างมากว่ามันเป็นไปไม่ได้เพราะมันจะเป็นปัญหาด้านความปลอดภัยอย่างไม่น่าเชื่อถ้าเป็นเช่นนั้น ตัวอย่างเช่นฉันสามารถสร้างหน้าเว็บที่ดูเหมือนหน้าเข้าสู่ระบบของธนาคารและทำให้ URL ในแถบที่อยู่ดูเหมือนกับธนาคารจริง !

บางทีถ้าคุณอธิบายว่าทำไมคุณถึงต้องการทำสิ่งนี้ผู้คนอาจจะสามารถแนะนำวิธีการอื่น ๆ ...

[แก้ไขในปี 2011: ตั้งแต่ฉันเขียนคำตอบนี้ในปี 2008 ข้อมูลเพิ่มเติมได้ชัดเจนเกี่ยวกับเทคนิค HTML5ที่ช่วยให้ URL สามารถแก้ไขได้ตราบใดที่มันมาจากแหล่งกำเนิดเดียวกัน]


6
มีปัญหาไม่มากนักหากการเปลี่ยนแปลงที่ไม่โหลดซ้ำถูก จำกัด ไว้ที่พา ธ สตริงข้อความค้นหาและส่วน - นั่นไม่ใช่สิทธิ์ (โดเมนและอื่น ๆ )
โอลลี่แซนเดอร์

2
youtube.com/user/SilkyDKwan#p/u/2/gTfqaGYVfMgเป็นตัวอย่างที่มันเป็นไปได้ลองเปลี่ยนวิดีโอ :)
Spidfire

คุณสามารถเปลี่ยน location.hash เท่านั้น (ทุกอย่างหลังจาก #) ตามที่ Matthew Chumley จดไว้ในคำตอบที่ยอมรับแล้ว
Paul Dixon

2
คุณใช้ Facebook หรือไม่ Facebook URL เปลี่ยนแปลงได้โดยไม่ต้องhistory.pushState()โหลดใช้
Derek 朕會功夫

Paul Dixon คุณควรสังเกตุเห็นกล่องขาเข้าของ Facebook เมื่อคุณคลิกที่ชื่อทางด้านซ้ายเพียงแค่เปลี่ยน URL และมีการโหลดการแชทใหม่ในกล่องแชทหน้าเว็บจะไม่รีเฟรช นอกจากนี้ยังมีเว็บไซต์อื่น ๆ อีกมากมายใน WebGL ที่พวกเขาทำเช่นเดียวกัน
Dheeraj Thedijje

8

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

วิธีเปลี่ยน URL ที่เชื่อถือได้โดยไม่ต้องเปลี่ยนหน้าคือการใช้ลิงค์ภายในหรือแฮช เช่น: http://site.com/page.htmlกลายเป็นhttp://site.com/page.html#item1 เทคนิคนี้มักใช้ใน hijax (AJAX + เก็บรักษาประวัติ)

เมื่อทำสิ่งนี้ฉันมักจะใช้ลิงก์สำหรับการดำเนินการกับแฮชเป็น href จากนั้นเพิ่มกิจกรรมการคลิกด้วย jquery ที่ใช้แฮชที่ร้องขอเพื่อกำหนดและมอบหมายการดำเนินการ

ฉันหวังว่าจะเป็นเส้นทางที่ถูกต้องสำหรับคุณ


ขออภัยคำตอบของคุณไม่เป็นความจริง ใช่คุณสามารถเปลี่ยน URL
Derek 朕會功夫

1
ใช่คุณสามารถใช้ html5 history api ได้ แต่ไม่ใช่ cross-browser แม้ว่าคุณสามารถใช้การเติมโพลีที่จะใช้แทนการแฮช URL
Jethro Larson

8

jQueryมีปลั๊กอินที่ดีสำหรับการเปลี่ยน URL เบราว์เซอร์เรียกว่าjQuery ดัน

JavaScript pushStateและ jQuery สามารถใช้ร่วมกันได้เช่น:

history.pushState(null, null, $(this).attr('href'));

ตัวอย่าง:

$('a').click(function (event) {

  // Prevent default click action
  event.preventDefault();     

  // Detect if pushState is available
  if(history.pushState) {
    history.pushState(null, null, $(this).attr('href'));
  }
  return false;
});


ใช้JavaScript เท่านั้นhistory.pushState()ซึ่งเปลี่ยนผู้อ้างอิงที่ถูกใช้ในส่วนหัว HTTP สำหรับวัตถุ XMLHttpRequest ที่สร้างขึ้นหลังจากที่คุณเปลี่ยนสถานะ

ตัวอย่าง:

window.history.pushState("object", "Your New Title", "/new-url");

วิธี pushState ():

pushState()ใช้สามพารามิเตอร์: วัตถุรัฐชื่อ (ซึ่งปัจจุบันถูกละเว้น) และ (เลือก) URL ลองตรวจสอบพารามิเตอร์ทั้งสามนี้โดยละเอียด

  1. วัตถุรัฐ - วัตถุรัฐเป็นวัตถุ JavaScript pushState()ซึ่งมีความเกี่ยวข้องกับประวัติศาสตร์รายการใหม่ที่สร้างขึ้นโดย เมื่อใดก็ตามที่ผู้ใช้นำทางไปยังสถานะใหม่เหตุการณ์ popstate จะเริ่มทำงานและคุณสมบัติสถานะของเหตุการณ์ประกอบด้วยสำเนาของวัตถุสถานะของรายการประวัติ

    วัตถุสถานะสามารถเป็นอะไรก็ได้ที่สามารถทำให้เป็นอันดับ เนื่องจาก Firefox บันทึกออบเจ็กต์สถานะลงในดิสก์ของผู้ใช้เพื่อให้สามารถเรียกคืนได้หลังจากที่ผู้ใช้รีสตาร์ทเบราว์เซอร์ของเราเราจึงกำหนดขนาดสูงสุดที่อักขระ 640k ในการแสดงสถานะของวัตถุแบบอนุกรม หากคุณผ่านวัตถุสถานะที่มีการแทนค่าแบบอนุกรมมีขนาดใหญ่กว่านี้pushState()วิธีจะส่งข้อยกเว้น หากคุณต้องการพื้นที่มากกว่านี้ขอแนะนำให้คุณใช้ sessionStorage และ / หรือ localStorage

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

  3. URL - URLของรายการประวัติใหม่ถูกกำหนดโดยพารามิเตอร์นี้ โปรดทราบว่าเบราว์เซอร์จะไม่พยายามโหลด URL นี้หลังจากมีการโทรpushState()แต่อาจพยายามโหลด URL ในภายหลังเช่นหลังจากผู้ใช้รีสตาร์ทเบราว์เซอร์ URL ใหม่ไม่จำเป็นต้องเป็นค่าสัมบูรณ์ หากเป็นแบบสัมพัทธ์จะถูกแก้ไขโดยสัมพันธ์กับ URL ปัจจุบัน URL ใหม่จะต้องมีต้นกำเนิดเดียวกันกับ URL ปัจจุบัน มิฉะนั้นpushState()จะส่งข้อยกเว้น พารามิเตอร์นี้เป็นทางเลือก หากไม่ได้ระบุไว้จะถูกตั้งค่าเป็น URL ปัจจุบันของเอกสาร



3

แกลเลอรี่รูปภาพของ Facebook ทำสิ่งนี้โดยใช้ #hash ใน URL นี่คือตัวอย่าง URL:

ก่อนคลิก 'ถัดไป':

/photo.php?fbid=496429237507&set=a.218088072507.133423.681812507&pid=5887027&id=681812507

หลังจากคลิก 'ถัดไป':

/photo.php?fbid=496429237507&set=a.218088072507.133423.681812507&pid=5887027&id=681812507#!/photo.php?fbid=496435457507&set=a.218088072507.133423.681812507&pid=5887085&id=681812507

หมายเหตุ hash-bang (#!) ตามด้วย URL ใหม่ทันที



2

สิ่งที่ทำงานให้ฉันคือ - history.replaceState()ฟังก์ชั่นซึ่งมีดังนี้ -

history.replaceState(data,"Title of page"[,'url-of-the-page']);

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


1

ฉันสงสัยว่ามันจะเป็นไปได้ไหมตราบใดที่พา ธ พาเรนต์ในหน้านั้นเหมือนกันมีเพียงสิ่งใหม่ที่ผนวกเข้ากับมัน

เช่นสมมติว่าผู้ใช้อยู่ที่หน้า: http://domain.com/site/page.html จากนั้นเบราว์เซอร์สามารถให้ฉันทำlocation.append = new.html และหน้ากลายเป็น: http://domain.com/site/page.htmlnew.htmlและเบราว์เซอร์ไม่เปลี่ยน

หรืออนุญาตให้บุคคลเปลี่ยนพารามิเตอร์รับดังนั้นลองมาดูlocation.get = me=1&page=1กัน

ดังนั้นหน้าดั้งเดิมจึงกลายเป็นhttp://domain.com/site/page.html?me=1&page=1และไม่รีเฟรช

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

จากสิ่งที่ฉันเห็นสิ่งประวัติศาสตร์ของ Yahoo โหลดข้อมูลทั้งหมดในครั้งเดียว ดูเหมือนจะไม่ทำคำขอ Ajax ใด ๆ ดังนั้นเมื่อ a divถูกใช้เพื่อจัดการเมธอดการทำงานล่วงเวลาที่แตกต่างกันข้อมูลนั้นจะไม่ถูกจัดเก็บสำหรับแต่ละสถานะประวัติ


1

รหัสของฉันคือ:

//change address bar
function setLocation(curLoc){
    try {
        history.pushState(null, null, curLoc);
        return false;
    } catch(e) {}
        location.hash = '#' + curLoc;
}

และการกระทำ:

setLocation('http://example.com/your-url-here');

และตัวอย่าง

$(document).ready(function(){
    $('nav li a').on('click', function(){
        if($(this).hasClass('active')) {

        } else {
            setLocation($(this).attr('href'));
        }
            return false;
    });
});

นั่นคือทั้งหมดที่ :)


1

คำตอบง่ายๆที่ฉันนำเสนอ

window.history.pushState(null, null, "/abc")

จะเพิ่ม/abcหลังจากชื่อโดเมนใน URL เบราว์เซอร์ เพียงคัดลอกรหัสนี้และวางในคอนโซลของเบราว์เซอร์แล้วดู URL ที่เปลี่ยนเป็น " https://stackoverflow.com/abc "


0

ฉันประสบความสำเร็จด้วย:

location.hash="myValue";

มันเพิ่งเพิ่ม#myValueไปยัง URL ปัจจุบัน หากคุณต้องการทริกเกอร์เหตุการณ์ในการโหลดหน้าคุณสามารถใช้สิ่งเดียวกันlocation.hashเพื่อตรวจสอบค่าที่เกี่ยวข้อง เพียงจำไว้ว่าให้ลบออก#จากค่าที่ส่งคืนโดยlocation.hashเช่น

var articleId = window.location.hash.replace("#","");
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.