Làm cách nào tôi có thể cập nhật window.location.hash mà không cần nhảy tài liệu?


163

Tôi có một bảng điều khiển trượt được thiết lập trên trang web của tôi.

Khi nó kết thúc hoạt hình, tôi đặt hàm băm như vậy

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

(đây là một cuộc gọi lại và idđược chỉ định trước đó).

Điều này hoạt động tốt, để cho phép người dùng đánh dấu bảng điều khiển và cũng để phiên bản không JavaScript hoạt động.

Tuy nhiên, khi tôi cập nhật hàm băm, trình duyệt sẽ nhảy đến vị trí. Tôi đoán đây là hành vi dự kiến.

Câu hỏi của tôi là: làm thế nào tôi có thể ngăn chặn điều này? Tức là làm thế nào tôi có thể thay đổi hàm băm của cửa sổ, nhưng không có trình duyệt cuộn đến phần tử nếu hàm băm tồn tại? Một số loại event.preventDefault()của điều?

Tôi đang sử dụng jQuery 1.4 và plugin scrollTo .

Cảm ơn nhiều!

Cập nhật

Đây là mã thay đổi bảng điều khiển.

$('#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
Tôi cho rằng bạn đã thử event.preventDefault():)
Marko

@Marko Tôi không biết đặt nó ở đâu!
alex

Bạn có thể gửi phần còn lại của mã của bạn?
Marko

@Marko Ivanovski Tôi không nghĩ nó có liên quan, nhưng tôi sẽ xem những gì tôi có thể làm.
alex

3
@Gareth Tôi không nghĩ rằng có một nơi dành cho nó, bởi vì nó xảy ra ngay khi tôi cập nhật hàm băm.
alex

Câu trả lời:


261

Có một cách giải quyết bằng cách sử dụng API lịch sử trên các trình duyệt hiện đại với dự phòng trên các trình duyệt cũ:

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

Tín dụng cho Lea Verou


Đây là câu trả lời tốt hơn, theo ý kiến ​​của tôi.
Greg Annandale

10
Lưu ý rằng PushState có tác dụng phụ (thụt lề) khi thêm trạng thái vào ngăn xếp lịch sử trình duyệt. Nói cách khác, khi người dùng nhấp vào nút quay lại, sẽ không có gì xảy ra trừ khi bạn cũng thêm một trình lắng nghe sự kiện popstate.
David Cook

32
@DavidCook - Chúng tôi cũng có thể sử dụng history.replaceState(mà, để thay đổi hàm băm, có thể có ý nghĩa hơn) để tránh sự cần thiết cho popstatengười nghe sự kiện.
Jack

Điều này làm việc cho tôi. Tôi thích hiệu ứng của sự thay đổi lịch sử. Tôi muốn thêm lời cảnh báo rằng điều này sẽ không kích hoạt hashchangesự kiện. Đó là điều tôi phải làm việc xung quanh.
Jordan

cảnh báo! điều này sẽ không kích hoạt một hashchangesự kiện
santiago arizti

52

Vấn đề là bạn đang đặt window.location.hash thành thuộc tính ID của phần tử. Đó là hành vi dự kiến ​​để trình duyệt nhảy đến phần tử đó, bất kể bạn có "ngăn chặn ()" hay không.

Một cách để khắc phục điều này là tiền tố băm với giá trị tùy ý như vậy:

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

Sau đó, tất cả những gì bạn cần làm là kiểm tra băm tiền tố khi tải trang. Là một phần thưởng bổ sung, bạn thậm chí có thể cuộn trơn tru vì nó hiện đang kiểm soát giá trị băm ...

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

Nếu bạn cần điều này để hoạt động mọi lúc (và không chỉ trên tải trang ban đầu), bạn có thể sử dụng chức năng để theo dõi các thay đổi đối với giá trị băm và chuyển đến phần tử chính xác khi đang di chuyển:

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

2
Đây là giải pháp duy nhất thực sự trả lời cho câu hỏi - cho phép băm mà không cần nhảy
amosmos

Điều này thực sự trả lời câu hỏi giải thích việc thêm và xóa giá trị tùy ý cho hàm băm để tránh bước nhảy theo hành vi mặc định của trình duyệt.
lowTechsun

1
giải pháp tốt, nhưng làm suy yếu giải pháp OP vì nó phủ nhận việc sử dụng các phần đánh dấu trang
Samus

27

Giải pháp rẻ tiền và khó chịu .. Sử dụng # xấu xí! Phong cách.

Để đặt nó:

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

Để đọc nó:

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

Vì nó không khớp và neo hoặc id trong trang, nên nó sẽ không nhảy.


3
Tôi đã phải duy trì khả năng tương thích với IE 7 và một số phiên bản di động của trang web. Giải pháp này là sạch nhất đối với tôi. Nói chung tôi sẽ có tất cả các giải pháp PushState.
Eric Goodwin

1
thiết lập hàm băm bằng: window.location.hash = '#/' + id;và sau đó thay thế nó bằng: window.location.hash.replace(/^#\//, '#');sẽ chỉnh sửa url một chút -> projects/#/tab1
braitsch

13

Tại sao bạn không có được vị trí cuộn hiện tại, đặt nó vào một biến sau đó gán hàm băm và đặt cuộn trang trở lại vị trí:

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

cái này nên hoạt động


1
hm, điều này đã làm việc cho tôi một lúc, nhưng đôi khi trong vài tháng qua, nó đã ngừng hoạt động trên firefox ....
matchew

10

Tôi đã sử dụng kết hợp giải pháp Attila Fulop (Lea Verou) cho các trình duyệt hiện đại và giải pháp Gavin Brock cho các trình duyệt cũ như sau:

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

Theo quan sát của Gavin Brock, để lấy lại id, bạn sẽ phải xử lý chuỗi (trong trường hợp này có thể có hoặc không có "!") Như sau:

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

Trước đó, tôi đã thử một giải pháp tương tự như giải pháp được đề xuất bởi user706270, nhưng nó không hoạt động tốt với Internet Explorer: vì công cụ Javascript của nó không nhanh lắm, bạn có thể nhận thấy sự tăng giảm cuộn xuống, tạo ra hiệu ứng hình ảnh khó chịu.


2

Giải pháp này đã làm việc cho tôi.

Vấn đề với cài đặt location.hashlà trang sẽ nhảy đến id đó nếu nó được tìm thấy trên trang.

Vấn đề với window.history.pushStatelà nó thêm một mục vào lịch sử cho mỗi tab mà người dùng nhấp vào. Sau đó, khi người dùng nhấp vào backnút, họ chuyển đến tab trước đó. (điều này có thể hoặc không thể là những gì bạn muốn. Nó không phải là những gì tôi muốn).

Đối với tôi, replaceStatelà tùy chọn tốt hơn ở chỗ nó chỉ thay thế lịch sử hiện tại, vì vậy khi người dùng nhấp vào backnút, họ sẽ chuyển đến trang trước đó.

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

Kiểm tra tài liệu API Lịch sử trên MDN.


1

Tôi không chắc liệu bạn có thể thay đổi thành phần gốc hay không nhưng làm thế nào về việc chuyển từ sử dụng id attr sang một thứ khác như data-id? Sau đó, chỉ cần đọc giá trị của id dữ liệu cho giá trị băm của bạn và nó sẽ không nhảy.


1

Giải pháp này hiệu quả với tôi

// 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');

Và mã js đầy đủ của tôi là

$('#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

Khi sử dụng khung laravel, tôi gặp một số vấn đề với việc sử dụng hàm route-> back () vì nó đã xóa hàm băm của tôi. Để giữ hàm băm của mình, tôi đã tạo một hàm đơn giản:

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

và tôi đặt nó trong hàm JS khác của mình như thế này:

localStorage.setItem("hash", myvalue);

Bạn có thể đặt tên cho các giá trị lưu trữ cục bộ của bạn theo bất kỳ cách nào bạn muốn; tôi tên hash.

Do đó, nếu hàm băm được đặt trên PAGE1 và sau đó bạn điều hướng đến PAGE2; hàm băm sẽ được tạo lại trên PAGE1 khi bạn nhấp vào Quay lại PAGE2.

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.