Sửa đổi chuỗi truy vấn mà không cần tải lại trang


114

Tôi đang tạo một thư viện ảnh và muốn có thể thay đổi chuỗi truy vấn và tiêu đề khi ảnh được duyệt.

Hành vi mà tôi đang tìm kiếm thường thấy với một số triển khai trang liên tục / vô hạn, trong khi bạn cuộn xuống chuỗi truy vấn vẫn tiếp tục tăng số trang ( http://x.com?page=4 ), v.v. Điều này nên về lý thuyết thì đơn giản, nhưng tôi muốn thứ gì đó an toàn trên các trình duyệt chính.

Tôi đã tìm thấy bài đăng tuyệt vời này và đang cố gắng làm theo ví dụ window.history.pushstate, nhưng điều đó dường như không hiệu quả với tôi. Và tôi không chắc liệu nó có lý tưởng hay không vì tôi không thực sự quan tâm đến việc sửa đổi lịch sử trình duyệt.

Tôi chỉ muốn có thể cung cấp khả năng đánh dấu ảnh hiện đang xem mà không cần tải lại trang mỗi khi ảnh được thay đổi.

Dưới đây là một ví dụ về trang vô hạn sửa đổi chuỗi truy vấn: http://tumbledry.org/

UPDATE đã tìm thấy phương pháp này:

window.location.href = window.location.href + '#abc';

nó có vẻ hoạt động với tôi, nhưng tôi đang sử dụng chrome mới .. nó có thể sẽ gây ra một số vấn đề với các trình duyệt cũ hơn?


Bạn có thể đăng một liên kết đến một số trang web mẫu có cập nhật động chuỗi truy vấn của nó không? Tôi không nghĩ rằng nó có thể được thực hiện, nhưng bạn có thể thay đổi giá trị băm và điều đó có thể đủ để đạt được những gì bạn muốn.
Pointy



có thể trùng lặp Tại sao Dropbox web mới có thể thay đổi URL mà không cần làm mới trang? và ba câu hỏi đó được đánh dấu là một bản sao của
Quentin

@Quentin. Bạn có thể chỉ có một phiếu bầu gần hơn ...:)
gdoron đang hỗ trợ Monica

Câu trả lời:


185

Nếu bạn đang tìm kiếm sửa đổi Hash, giải pháp của bạn hoạt động tốt. Tuy nhiên, nếu bạn muốn thay đổi truy vấn, bạn có thể sử dụng pushState, như bạn đã nói. Đây là một ví dụ có thể giúp bạn triển khai nó đúng cách. Tôi đã thử nghiệm và nó hoạt động tốt:

if (history.pushState) {
    var newurl = window.location.protocol + "//" + window.location.host + window.location.pathname + '?myNewUrlQuery=1';
    window.history.pushState({path:newurl},'',newurl);
}

Nó không tải lại trang mà chỉ cho phép bạn thay đổi truy vấn URL. Bạn sẽ không thể thay đổi giao thức hoặc các giá trị máy chủ. Và tất nhiên, nó yêu cầu các trình duyệt hiện đại có thể xử lý API Lịch sử HTML5.

Để biết thêm thông tin:

http://diveintohtml5.info/history.html

https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulation_the_browser_history


6
Tôi tin rằng bạn có thể rút ngắn window.location.protocol + '//' + window.location.hostxuống còn: window.location.origin.
Garrett vào

4
Ngoài ra, để biết thêm một chút thông tin, các đường dẫn tương đối cũng hoạt động với history.pushState(). Không statecần đối số thực tế . Cả hai điều này có nghĩa là bạn có thể làm điều gì đó đơn giản như history.pushState(null, '', '/foo?bar=true')nếu url mới của bạn nằm trên cùng một máy chủ / cổng.
Blaskovicz

23
Lưu ý rằng, nếu bạn không muốn trạng thái mới xuất hiện trên lịch sử trình duyệt, bạn có thể sử dụng history.replaceState()với các đối số tương tự.
Blackus

6
SỬ DỤNG history.replaceState () nếu không bạn cần phải bấm nút BACK gấp đôi trong trình duyệt của bạn
Zhenya

4
trong các trình duyệt hiện đại, bạn chỉ có thể làm:if (window.history.pushState) { const newURL = new URL(window.location.href); newURL.search = '?myNewUrlQuery=1'; window.history.pushState({ path: newURL.href }, '', newURL.href); }
Allan Baptista

8

Dựa trên câu trả lời của Fabio, tôi đã tạo ra hai hàm có thể hữu ích cho bất kỳ ai gặp phải câu hỏi này. Với hai hàm này, bạn có thể gọi insertParam()với khóa và giá trị làm đối số. Nó sẽ thêm tham số URL hoặc, nếu một tham số truy vấn đã tồn tại với cùng một khóa, nó sẽ thay đổi tham số đó thành giá trị mới:

//function to remove query params from a URL
function removeURLParameter(url, parameter) {
    //better to use l.search if you have a location/link object
    var urlparts= url.split('?');   
    if (urlparts.length>=2) {

        var prefix= encodeURIComponent(parameter)+'=';
        var pars= urlparts[1].split(/[&;]/g);

        //reverse iteration as may be destructive
        for (var i= pars.length; i-- > 0;) {    
            //idiom for string.startsWith
            if (pars[i].lastIndexOf(prefix, 0) !== -1) {  
                pars.splice(i, 1);
            }
        }

        url= urlparts[0] + (pars.length > 0 ? '?' + pars.join('&') : "");
        return url;
    } else {
        return url;
    }
}

//function to add/update query params
function insertParam(key, value) {
    if (history.pushState) {
        // var newurl = window.location.protocol + "//" + window.location.host + search.pathname + '?myNewUrlQuery=1';
        var currentUrlWithOutHash = window.location.origin + window.location.pathname + window.location.search;
        var hash = window.location.hash
        //remove any param for the same key
        var currentUrlWithOutHash = removeURLParameter(currentUrlWithOutHash, key);

        //figure out if we need to add the param with a ? or a &
        var queryStart;
        if(currentUrlWithOutHash.indexOf('?') !== -1){
            queryStart = '&';
        } else {
            queryStart = '?';
        }

        var newurl = currentUrlWithOutHash + queryStart + key + '=' + value + hash
        window.history.pushState({path:newurl},'',newurl);
    }
}

làm thế nào các chức năng của bạn tốt hơn so new URLSearchParams()với các phương thức gốc của nó như thiết lậpxóa ? trong cả hai trường hợp chúng tôi phải đưa nó vào lịch sử vớihistory.pushState()
AlexNikonov

1
new URLSearchParams()không được hỗ trợ bởi bất kỳ phiên bản của trình duyệt IE
jmona789

Cảm ơn bạn @ jmona789, điều này hoàn toàn phù hợp với tôi và chính xác là những gì tôi đang tìm kiếm
mknopf

7

Tôi đã sử dụng thư viện JavaScript sau với thành công lớn:

https://github.com/balupton/jquery-history

Nó hỗ trợ API lịch sử HTML5 cũng như một phương pháp dự phòng (sử dụng #) cho các trình duyệt cũ hơn.

Thư viện này thực chất là một polyfill xung quanh `history.pushState '.


tuyệt vời! bạn đã kiểm tra nó với tất cả các trình duyệt ??
Sonic Soul

Việc triển khai của tôi đã được thử nghiệm trong IE7 +, Firefox 3.6+, Safari 5 và Chrome 16+. Nó có thể cũng hoạt động với các trình duyệt khác, nhưng tôi không có bất kỳ phàn nàn nào trong một số hệ thống được triển khai sử dụng nó.
Ian Newson

tuyệt quá. vì vậy ngay bây giờ .. chỉ cần đặt # thay vì & khi ghi vào window.location.href là phù hợp với tôi. trong đó nó không tải lại trang. tôi chắc chắn rằng nó sẽ bị hỏng khi tôi kiểm tra nó trong IE .. lúc đó tôi sẽ sử dụng thư viện mà bạn đề xuất. cảm ơn
Sonic Soul

Phương pháp # là một phương pháp tốt ở chỗ nó hỗ trợ trình duyệt rất rộng. Mọi thứ có thể trở nên phức tạp khi bạn cần đưa thông tin đó vào các yêu cầu tới máy chủ, vì phần # của URL không được trình duyệt gửi. Có nhiều cách làm tròn điều đó, bao gồm cả thư viện mà tôi đã tham khảo. Ngoài ra, việc sử dụng API lịch sử HTML5 giúp làm cho URL của bạn ngắn hơn về tổng thể và yêu cầu ít công việc phía khách hàng hơn để khôi phục trạng thái.
Ian Newson

Phương pháp # cũng có vấn đề đối với việc chia sẻ trên mạng xã hội; Twitter, Facebook và có thể những người khác không hoạt động tốt với thẻ neo khi tạo bản xem trước hoặc liên kết quay lại phần chia sẻ.
mirth23

5

Tôi muốn cải thiện câu trả lời của Fabio và tạo một hàm thêm khóa tùy chỉnh vào chuỗi URL mà không cần tải lại trang.

function insertUrlParam(key, value) {
    if (history.pushState) {
        let searchParams = new URLSearchParams(window.location.search);
        searchParams.set(key, value);
        let newurl = window.location.protocol + "//" + window.location.host + window.location.pathname + '?' + searchParams.toString();
        window.history.pushState({path: newurl}, '', newurl);
    }
}

0

Sau đó, API lịch sử chính xác là những gì bạn đang tìm kiếm. Nếu bạn cũng muốn hỗ trợ các trình duyệt cũ, thì hãy tìm một thư viện quay lại thao tác với thẻ băm của URL nếu trình duyệt không cung cấp API lịch sử.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.