문서를 뛰어 넘지 않고 window.location.hash를 어떻게 업데이트합니까?


163

웹 사이트에 슬라이딩 패널이 설치되어 있습니다.

애니메이션이 끝나면 해시를 이렇게 설정했습니다.

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

(이것은 콜백이며 id는 이전에 할당됩니다).

이는 사용자가 패널을 책갈피에 추가하고 JavaScript 이외의 버전에서도 작동하도록하는 데 효과적입니다.

그러나 해시를 업데이트하면 브라우저가 해당 위치로 이동합니다. 나는 이것이 예상되는 행동이라고 생각한다.

내 질문은 : 어떻게 이것을 막을 수 있습니까? 즉, 어떻게 창의 해시를 변경할 수 있지만 해시가 존재하는 경우 브라우저가 요소로 스크롤 되지 않습니까? 어떤 종류의 event.preventDefault()것?

jQuery 1.4와 scrollTo 플러그인을 사용하고 있습니다 .

많은 감사합니다!

최신 정보

다음은 패널을 변경하는 코드입니다.

$('#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
나는 당신이 시도했다고 가정 event.preventDefault():)
Marko

@Marko 나는 그것을 어디에 둘지 모른다!
alex

나머지 코드를 게시 할 수 있습니까?
Marko

@Marko Ivanovski 나는 그것이 관련성이 없다고 생각하지만, 내가 할 수있는 것을 볼 것이다.
alex

3
@Gareth 해시를 업데이트하자마자 발생하기 때문에 장소가 있다고 생각하지 않습니다.
alex

답변:


261

최신 브라우저에서 히스토리 API를 사용하여 이전 브라우저에서 대체 할 수있는 해결 방법이 있습니다.

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

크레딧은 Lea Verou 로갑니다


제 생각에는 이것이 더 나은 대답입니다.
Greg Annandale

10
pushState는 브라우저 기록 스택에 상태를 추가하는 부작용 (들여 쓰기)을 나타냅니다. 즉, 사용자가 뒤로 단추를 클릭하면 popstate 이벤트 리스너도 추가하지 않으면 아무 일도 일어나지 않습니다.
David Cook

32
@DavidCook- 이벤트 리스너 history.replaceState의 필요성을 피하기 위해 해시 변경에 더 적합 할 수도 있습니다 popstate.
Jack

이것은 나를 위해 일했습니다. 나는 역사 변화의 효과를 좋아한다. 이것이 hashchange이벤트를 트리거하지 않을 것이라는 경고를 추가하고 싶습니다 . 그것은 내가 해결해야 할 일이었습니다.
Jordan

경고! 이것은 hashchange이벤트를 트리거하지 않습니다
santiago arizti

52

문제는 window.location.hash 를 요소의 ID 속성 으로 설정하는 것입니다. "preventDefault ()"여부에 관계없이 브라우저가 해당 요소로 이동하는 것이 예상되는 동작입니다.

이 문제를 해결하는 한 가지 방법은 해시 앞에 임의의 값을 붙이는 것입니다.

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

그런 다음 페이지로드시 접두사가 붙은 해시를 확인하기 만하면됩니다. 추가 보너스로 해시 값을 제어 할 수 있으므로 부드럽게 스크롤 할 수도 있습니다 ...

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

초기 페이지로드뿐만 아니라 항상 작동 해야하는 경우 함수를 사용하여 해시 값의 변경 사항을 모니터링하고 즉시 올바른 요소로 이동할 수 있습니다.

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

2
이것은 실제로 질문에 대답하는 유일한 솔루션입니다-점프하지 않고 해싱 허용
amosmos

이것은 기본 브라우저 동작에 따라 점프를 피하기 위해 해시의 임의 값 추가 및 삭제를 설명하는 질문에 실제로 대답합니다.
lowtechsun

1
좋은 솔루션이지만 북마크 섹션 사용을 무효화하여 OP 솔루션을 약화시킵니다
Samus

27

싸고 불쾌한 솔루션 .. 못생긴 #를 사용하십시오! 스타일.

설정하려면 :

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

그것을 읽으려면 :

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

페이지에서 일치하지 않고 앵커 또는 ID가 없으므로 점프하지 않습니다.


3
IE 7 및 일부 모바일 버전의 사이트와의 호환성을 유지해야했습니다. 이 솔루션은 가장 깨끗했습니다. 일반적으로 나는 pushState 솔루션을 다룰 것입니다.
Eric Goodwin

1
해시를 설정 window.location.hash = '#/' + id;하고 다음으로 바꾸십시오 : window.location.hash.replace(/^#\//, '#');URL을 조금 prettify합니다-> projects/#/tab1
braitsch

13

현재 스크롤 위치를 가져 와서 변수에 넣은 다음 해시를 할당하고 페이지 스크롤을 원래 위치로 다시 넣으십시오.

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

이 작동합니다


1
흠, 이것은 잠시 동안 나를 위해 일하고 있었지만, 지난 몇 달 동안 파이어 폭스에서 작동이 중지되었습니다 ....
matchew

10

최신 브라우저에는 Attila Fulop (Lea Verou) 솔루션과 이전 브라우저에는 Gavin Brock 솔루션을 다음과 같이 조합하여 사용했습니다.

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

Gavin Brock이 관찰 한 것처럼 id를 다시 캡처하려면 다음과 같이 문자열 (이 경우 "!"가 있거나없는)을 처리해야합니다.

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

그 전에 user706270에서 제안한 것과 비슷한 솔루션을 시도했지만 Internet Explorer에서는 제대로 작동하지 않습니다. Javascript 엔진이 빠르지 않기 때문에 스크롤 속도가 빨라져서 시각적 효과가 좋지 않습니다.


2

이 솔루션은 저에게 효과적이었습니다.

설정 문제 location.hash는 페이지에서 페이지가 발견되면 해당 ID로 점프한다는 것입니다.

문제 window.history.pushState는 사용자가 클릭하는 각 탭의 기록에 항목을 추가한다는 것입니다. 그런 다음 사용자가 back버튼을 클릭 하면 이전 탭으로 이동합니다. (이것은 당신이 원하는 것일 수도 아닐 수도 있습니다. 그것은 내가 원하는 것이 아니 었습니다).

나를 위해, replaceState그것은 현재 기록 만 대체한다는 점에서 더 나은 옵션이었습니다. 따라서 사용자가 back버튼을 클릭 하면 이전 페이지로 이동합니다.

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

MDN 에서 History API 문서 를 확인하십시오 .


1

원래 요소를 변경할 수 있는지 확실하지 않지만 id attr 사용을 data-id와 같은 것으로 바꾸는 방법은 무엇입니까? 그런 다음 해시 값에 대한 data-id 값을 읽으면 점프하지 않습니다.


1

이 솔루션은 저에게 효과적이었습니다.

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

그리고 내 전체 JS 코드는

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

laravel 프레임 워크를 사용할 때 해시가 지워지기 때문에 route-> back () 함수를 사용하는 데 문제가있었습니다. 해시를 유지하기 위해 간단한 함수를 만들었습니다.

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

그리고 다른 JS 함수에서 다음과 같이 설정했습니다.

localStorage.setItem("hash", myvalue);

원하는 방식으로 로컬 스토리지 값의 이름을 지정할 수 있습니다. 내 이름이 hash.

따라서 해시가 PAGE1에 설정된 경우 PAGE2로 이동합니다. PAGE2에서 뒤로를 클릭하면 PAGE1에서 해시가 다시 작성됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.