Ubah URL di browser tanpa memuat halaman baru menggunakan JavaScript

297

Bagaimana saya memiliki tindakan JavaScript yang mungkin memiliki beberapa efek pada halaman saat ini tetapi juga akan mengubah URL di browser sehingga jika pengguna mengklik memuat ulang atau bookmark, maka URL baru digunakan?

Akan lebih baik jika tombol kembali memuat ulang URL asli.

Saya mencoba merekam status JavaScript di URL.

Steven Noble
sumber
1
Ini akan sangat menyenangkan. Tentu saja itu akan terbatas pada modifikasi domain yang sama. Tetapi beberapa kontrol sisi klien dari jalur (dan bukan hanya hash) adalah langkah logis sekarang karena memuat kembali halaman adalah semacam "pilihan terakhir" untuk banyak aplikasi.
harpo
1
Sebuah "semacam" penggunaan yang baik dari 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 朕 會 功夫
contoh efek ini dalam aksi: dujour.com
Ben
2
Contoh efek ini: facebook.com (Saat membuka gambar di lightbox)
ini pertanyaan yang bagus. Namun, ini situasi yang menyedihkan karena jika pertanyaan ini diajukan hari ini, pertanyaan itu akan dibatalkan dan dilompati oleh "ini bukan jenis situs yang membuat orang-orang menulis semua kode Anda untuk Anda".
dewd

Jawaban:

118

Dengan HTML 5, gunakan history.pushStatefungsinya . Sebagai contoh:

<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>

dan href:

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

Jika Anda ingin mengubah URL tanpa menambahkan entri ke daftar tombol kembali, gunakan history.replaceStatesaja.

clu3
sumber
Anda benar, terakhir kali saya bereksperimen dengan Chrome. Saya baru saja mencoba dengan Firefox 3.6 di Ubuntu saya, itu tidak berhasil. Saya kira kita harus menunggu sampai HTML5 sepenuhnya didukung di FF
clu3
15
Kode sampel dipotong dan disisipkan dari developer.mozilla.org/en/DOM/Manipulating_the_browser_history . Yang sebenarnya mengganggu menjelaskan apa arti foo dan bar dalam kasus ini.
mikemaccana
2
Foo and bar tidak berarti apa-apa, itu adalah objek negara yang ditentukan secara sewenang-wenang yang dapat Anda dapatkan kembali nanti.
Paul Dixon
3
@ Paul: ya, artikel di atas memberikan info itu.
mikemaccana
2
SEBAGAI posting komentar ini berfungsi pada firefox chrome dan safari. Tidak beruntung dengan safari seluler di ipad atau iphone :(
Sid
187

Jika Anda ingin bekerja di browser yang tidak mendukung history.pushStatedan history.popStatebelum, "lama" cara adalah untuk mengatur identifier fragmen, yang tidak akan menyebabkan reload halaman.

Ide dasarnya adalah mengatur window.location.hashproperti ke nilai yang berisi informasi status apa pun yang Anda perlukan, lalu gunakan window.onhashchange event , atau untuk browser lama yang tidak mendukung onhashchange(IE <8, Firefox <3.6), periksa secara berkala untuk lihat apakah hash telah berubah (menggunakan setIntervalmisalnya) dan perbarui halaman. Anda juga perlu memeriksa nilai hash pada pemuatan halaman untuk mengatur konten awal.

Jika Anda menggunakan jQuery ada plugin hashchange yang akan menggunakan metode apa pun yang didukung browser. Saya yakin ada plugin untuk perpustakaan lain juga.

Satu hal yang perlu diperhatikan adalah bertabrakan dengan id pada halaman, karena browser akan menggulir ke elemen apa pun dengan id yang cocok.

Matthew Crumley
sumber
2
Jangan mesin pencari mengabaikan tautan internal ini (hash)? Dalam skenario saya, saya ingin laba-laba mengambil tautan ini juga.
Drew Noakes
3
@Rew, sejauh yang saya tahu, tidak ada cara bagi mesin pencari untuk memperlakukan bagian halaman sebagai hasil yang terpisah.
Matthew Crumley
8
Sekarang ada proposal untuk membuat mesin pencari melihat hash: googlewebmastercentral.blogspot.com/2009/10/…
LKM
5
Alih-alih menggunakan setIntervaluntuk memeriksa orang document.location.hashdapat menggunakan hashchangeacara tersebut, karena itu jauh lebih diadopsi. Periksa di sini untuk browser apa yang mendukung setiap standar . Pendekatan saya saat ini adalah dengan menggunakan push / popState pada browser yang mendukungnya. Pada yang lain saya mengatur hash dan hanya menonton hashchangedi browser yang mendukung. Ini membuat IE <= 7 tanpa dukungan riwayat, tetapi dengan permalink yang berguna. Tapi siapa yang peduli dengan IE <= 7 sejarah?
Irae Carvalho
2
@ gabeDel Ya, meskipun saya pikir Analytics tidak mencatat hash, jadi URL-nya akan sama. Cara yang lebih baik adalah dengan menelepon secara manual _trackPageviewdengan URL "asli" dari halaman baru.
Matthew Crumley
37

window.location.href berisi URL saat ini. Anda dapat membacanya, Anda dapat menambahkannya, dan Anda dapat menggantinya, yang dapat menyebabkan pemuatan ulang halaman.

Jika, seperti kedengarannya, Anda ingin merekam status javascript di URL sehingga dapat di-bookmark, tanpa memuat ulang halaman, tambahkan ke URL saat ini setelah # dan memiliki sepotong javascript yang dipicu oleh peristiwa onload mengurai arus saat ini URL untuk melihat apakah mengandung negara yang disimpan.

Jika Anda menggunakan? alih-alih #, Anda akan memaksa memuat ulang halaman, tetapi karena Anda akan mem-parsing status yang disimpan saat dimuat, ini mungkin sebenarnya bukan masalah; dan ini akan membuat tombol maju dan mundur bekerja dengan benar juga.

bayangan bulan
sumber
2
merekam status javascript di URL adalah persis apa yang saya coba lakukan
Steven Noble
21

Saya akan sangat curiga ini tidak mungkin, karena itu akan menjadi masalah keamanan yang luar biasa. Misalnya, saya dapat membuat halaman yang terlihat seperti halaman login bank, dan membuat URL di bilah alamat terlihat seperti bank asli !

Mungkin jika Anda menjelaskan mengapa Anda ingin melakukan ini, orang-orang mungkin dapat menyarankan pendekatan alternatif ...

[Sunting pada 2011: Sejak saya menulis jawaban ini pada 2008, lebih banyak info terungkap mengenai teknik HTML5 yang memungkinkan URL untuk dimodifikasi asalkan berasal dari sumber yang sama]

Paul Dixon
sumber
6
Tidak terlalu menjadi masalah jika perubahan non-reload dibatasi untuk jalur, string kueri, dan fragmen — yaitu bukan otoritas (domain dan semacamnya).
Ollie Saunders
2
youtube.com/user/SilkyDKwan#p/u/2/gTfqaGYVfMg adalah contoh yang mungkin, coba
alihkan
Anda hanya dapat mengubah location.hash (semuanya setelah #), seperti yang dicatat oleh Matthew Chumley dalam jawaban yang diterima.
Paul Dixon
2
Apakah kamu menggunakan facebook? Facebook mengubah URL tanpa memuat ulang, menggunakan history.pushState().
Derek 朕 會 功夫
Paul Dixon, Anda harus melihat kotak masuk Facebook, ketika Anda mengklik nama-nama di sebelah kiri, URL saja diubah dan obrolan baru dimuat di kotak obrolan, halaman tidak di-refresh. juga ada lebih banyak situs di WebGL mereka melakukan hal yang sama
Dheeraj Thedijje
8

Pengaturan keamanan browser mencegah orang mengubah url yang ditampilkan secara langsung. Anda bisa membayangkan kerentanan phishing yang akan menyebabkan.

Hanya cara andal untuk mengubah url tanpa mengubah halaman adalah dengan menggunakan tautan internal atau hash. misalnya: http://site.com/page.html menjadi http://site.com/page.html#item1 . Teknik ini sering digunakan dalam hijax (AJAX + preserve history).

Ketika melakukan ini, saya akan sering menggunakan tautan untuk tindakan dengan hash sebagai href, lalu menambahkan acara klik dengan jquery yang menggunakan hash yang diminta untuk menentukan dan mendelegasikan tindakan.

Saya harap itu menempatkan Anda di jalan yang benar.

Jethro Larson
sumber
Maaf tetapi jawaban Anda tidak benar. Ya, Anda dapat mengubah URL.
Derek 朕 會 功夫
1
Ya, Anda dapat menggunakan api riwayat html5 tetapi itu bukan lintas-peramban, meskipun Anda dapat menggunakan poli-isi yang akan mundur ke url hash.
Jethro Larson
8

jQuery memiliki plugin yang bagus untuk mengubah URL browser, yang disebut jQuery-pusher .

JavaScript pushStatedan jQuery dapat digunakan bersama, seperti:

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

Contoh:

$('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;
});

Hanya menggunakan JavaScript history.pushState() , yang mengubah pengarah, yang digunakan di header HTTP untuk objek XMLHttpRequest yang dibuat setelah Anda mengubah status.

Contoh:

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

Metode pushState ():

pushState()mengambil tiga parameter: objek keadaan, judul (yang saat ini diabaikan), dan (opsional) URL. Mari kita periksa masing-masing dari ketiga parameter ini secara lebih rinci:

  1. state object - Objek state adalah objek JavaScript yang dikaitkan dengan entri riwayat baru yang dibuat oleh pushState(). Setiap kali pengguna menavigasi ke negara baru, acara popstate dipecat, dan properti negara acara berisi salinan objek negara entri sejarah.

    Objek state dapat berupa apa saja yang dapat diserialisasi. Karena Firefox menyimpan objek negara ke disk pengguna sehingga dapat dipulihkan setelah pengguna me-restart browser-nya, kami memaksakan batas ukuran 640k karakter pada representasi serial objek negara. Jika Anda melewatkan objek negara yang representasi bersambung lebih besar dari ini pushState(), metode akan mengeluarkan pengecualian. Jika Anda membutuhkan lebih banyak ruang daripada ini, Anda dianjurkan untuk menggunakan sessionStorage dan / atau localStorage.

  2. title - Firefox saat ini mengabaikan parameter ini, meskipun mungkin menggunakannya di masa depan. Melewati string kosong di sini harus aman terhadap perubahan metode di masa mendatang. Atau, Anda bisa memberikan judul pendek untuk status yang Anda pindahkan.

  3. URL - URL entri riwayat baru diberikan oleh parameter ini. Perhatikan bahwa browser tidak akan mencoba memuat URL ini setelah panggilan ke pushState(), tetapi mungkin berusaha memuat URL nanti, misalnya setelah pengguna me-restart browser-nya. URL baru tidak harus mutlak; jika itu relatif, itu diselesaikan relatif terhadap URL saat ini. URL baru harus memiliki asal yang sama dengan URL saat ini; jika tidak, pushState()akan melempar pengecualian. Parameter ini opsional; jika tidak ditentukan, itu diatur ke URL dokumen saat ini.

Ilia Rostovtsev
sumber
3

Galeri foto Facebook melakukan ini menggunakan hash di URL. Berikut beberapa contoh URL:

Sebelum mengklik 'berikutnya':

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

Setelah mengklik 'berikutnya':

/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

Perhatikan hash-bang (#!) Segera diikuti oleh URL baru.

Bukit Jonathon
sumber
2

Apa yang berfungsi untuk saya adalah - history.replaceState()fungsi yaitu sebagai berikut -

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

Ini tidak akan memuat ulang halaman, Anda dapat memanfaatkannya dengan acara javascript

Veshraj Joshi
sumber
1

Saya bertanya-tanya apakah itu akan mungkin selama jalur induk di halaman itu sama, hanya sesuatu yang baru ditambahkan ke sana.

Jadi seperti katakanlah pengguna ada di halaman: http://domain.com/site/page.html Lalu browser dapat membiarkan saya melakukannya location.append = new.html dan halaman menjadi: http://domain.com/site/page.htmlnew.htmldan browser tidak mengubahnya.

Atau cukup izinkan orang itu mengubah parameter get, jadi mari kita location.get = me=1&page=1.

Jadi halaman asli menjadi http://domain.com/site/page.html?me=1&page=1dan tidak menyegarkan.

Masalah dengan # adalah bahwa data tidak di-cache (setidaknya saya tidak berpikir begitu) ketika hash diubah. Jadi itu seperti setiap kali halaman baru sedang dimuat, sedangkan tombol back-and forward di halaman non- Ajax dapat men-cache data dan tidak menghabiskan waktu untuk memuat ulang data.

Dari apa yang saya lihat, hal sejarah Yahoo sudah memuat semua data sekaligus. Tampaknya tidak melakukan permintaan Ajax. Jadi ketika a divdigunakan untuk menangani metode lembur yang berbeda, data itu tidak disimpan untuk setiap status riwayat.

pengguna58670
sumber
1

kode saya adalah:

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

dan tindakan:

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

dan contoh

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

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

Itu saja :)

Tusko Trush
sumber
1

Saya berikan jawaban yang lebih sederhana,

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

ini akan ditambahkan /abcsetelah nama domain di URL browser. Cukup salin kode ini dan rekatkan di konsol browser dan lihat URL berubah menjadi " https://stackoverflow.com/abc "

Sam
sumber
0

Saya sudah sukses dengan:

location.hash="myValue";

Itu hanya menambah #myValueURL saat ini. Jika Anda perlu memicu suatu acara di halaman Muat, Anda dapat menggunakan yang sama location.hashuntuk memeriksa nilai yang relevan. Hanya ingat untuk menghapus #dari nilai yang dikembalikan oleh location.hashmis

var articleId = window.location.hash.replace("#","");
Adam Hey
sumber