JavaScript2019. 5. 21. 23:41
반응형

웹 페이지를 작성하면 A(anchor)태그에 javascriptfunction을 통한 동작을 수행할 경우에 href 속성에 javascript:void(0)#가 작성된 코드를 만나게 됩니다. 이 경우에 과연 어떤것을 쓰는것이 맞는 것인가에 대한 궁금증이 생겨 비교해보았습니다.

javascript:void(0)

javascript:를 사용할 경우 해당 구문이 스크립트로 평가되어 실행되어 도큐멘트의 내용으로 표시됩니다.

<a href="javascript:'테스트입니다.'">클릭</a>

위와 같이 작성된 A태그가 있다면 클릭할 경우 화면의 내용이 테스트입니다. 으로 전환됩니다.

<a href="javascript:void(0);">클릭</a>

void(0)를 사용할 경우에는 스크립트의 평가 결과로 undefined가 반환되어 무시되므로 현재 페이지가 유지됩니다. 혹시 javascript가 지원되지 않거나 무효화 되어있는 브라우저의 경우에는 마찬가지로 현재 페이지가 유지됩니다.

 

void(0) 실행결과

브라우저 개발자 모드의 console에서 void(0)를 실행한 결과 undefined가 출력되는 것을 볼 수 있다.

일반적으로 사용하는데 큰 문제는 없지만 CSP(Content Security Policy)의 설정에 따라서는 Inline Event Handler가 블럭될 수 있습니다.(물론 void이므로 블럭된다해서 문제될 것은 없을 수 있지만 보안툴 등에 의해 경고가 출력될 수 있습니다.)

CSP에 대해서 간단하게 설명드리면 지정한 정책에 따라 동작이 다르기는 하겠지만 기본적으로 위험한 스크립트가 실행되는 상황을 배제하기 위한 정책이라고 보시면 됩니다. XSS(Cross site script) 취약점에 의해서 외부의 스크립트가 주입되어 실행되는 것을 차단하기 위해서 인라인 스크립트(Inline script)를 사용하지 못하게 할 수 있습니다. 물론 실제로 그 정책을 적용하는 곳은 아직 드물기 합니다. 따라서 장기적인 관점에서 인라인 스크립트의 사용을 줄어가는 노력을 할 필요가 있어보입니다.

#(hash)

#(hash)는 보통 페이지 내부링크를 목적으로 사용되는데 id를 지정하지 않은 경우에는 해당 페이지의 최상단으로 스크롤됩니다. 기본동작을 방지하기 위해서는 클릭 이벤트 핸들러에서 false를 반환하거나 이벤트의 preventDefault를 호출해 주어야 합니다.

<script>
    function somehandler() {
        return false;
    }
</script>
<a href="#" onclick="somehandler()">클릭</a>
<a href="#" id="someid">클릭</a>
$("#someid").click(function(e) {
  //...
  e.preventDefault();
});

onclick속성을 이용해서 인라인 이벤트 핸들러(Inline Event Handler)를 사용하는 것은 마찬가지로 CSP(Contents Security Policy)를 위반하는 문제가 있으므로 가급적 지양하는 것이 바람직 할 듯 합니다. 위의 예제와 같이 jQuery를 이용하거나 addEventListener를 이용하여 이벤트 핸들러를 등록하시는 것을 추천 드립니다.

위의 예제에서 javascript 별도의 파일로 분리해야 CSP에 위배되지 않습니다. <script>태크도 인라인 스크립트에 해당합니다.

경우에 따라서는 #notexist와 같이 존재하지 않는 태그를 사용하는 방법도 있습니다만 개인적으로는 존재하지 않는 아이디를 설정하는 것이 문제가 아닌가 하는 생각이 듭니다. 다만 이 경우에는 위와같은 트릭을 쓰지않아도 무시되므로 편할 수 있습니다. 이부분은 각 개발팀별로 합의하에 적용하시면 될 것 같습니다.

혹시 전체적으로 preventDefault()를 호출하는 것이 불편하다고 생각하는 분들은 아래의 코드와 같이 jQuery등을 사용하여 일괄적으로 적용할 수 있습니다.

$('a[href="#"]').click(function(e) {
    e.preventDefault();
});

Button 사용하기

개인적으로는 가장 추천 드리는 방법입니다. A태그는 사실 어딘가로 네비게이션해주는 의미가 있는 태그입니다. 따라서 이동이 없는 요소는 가급적 A태그를 사용하지 않는 것을 추천드립니다. 그리고 form을 제출(submit)하는 버튼의 경우에는 input="submit"을 사용하는 것이 웹표준이나 사용성 측면(엔터키에 의한 제출이 가능해짐)에서바람직 합니다.

<style>
    button.click {
        background: transparent;
        border: none;
        outline: 0;
    }
</style>
<button class="click">클릭</button>

모든 경우에 적용할 수는 없겠지만 위와같이 버튼의 디자인을 텍스트만 나오게 변경할 수도 있을것입니다.

빈 href 속성 사용하기

가끔 href=""와 같이 기술하시는 분들도 있습니다. 다른 옵션들은 무조건 사용하지 않아야 한다라고 말씀드리기는 애매한 측면이 있지만 빈 href는 사용하지 마시라고 말씀드리고 싶습니다. 물론 빈 href#를 사용하는 경우와 동일하게 return false를 이용하면 같은 효과를 낼 수 있습니다. 다만 이경우 href=""는 현재 접속한 페이지에의 링크와 동일한 의미로 해석된다는 점에 주의해야 합니다.

지금은 브라우저 등에서 차단해주기도 합니다만 같은 원리로 img태그의 src속성도 빈값을 넣게 되면 현재 접속중인 페이지를 외부 리소스로 불러오게 되어 같은 페이지를 두번 불러오는 효과가 나기도 합니다. 한번만 접속하게 되있는 페이지 등에서 문제를 일으키기도 했습니다.

차단해 주지 않는 브라우저를 감안해서 img src=""는 일괄적으로 찾아서 변경할 필요가 있습니다.

마치며

이 부분은 사실 의견이 갈릴 수도 있어서 조심스럽습니다만 필자의 생각으로는 가능한 Button을 사용하는 것이 바람직해보입니다. 다만 디자인상 어쩔수 없는 경우가 있으므로 그럴 경우에는 CSP문제가 발생하지 않도록 주의하여 #를 사용하는 것을 추천드립니다.

참고자료

Which “href” value should I use for JavaScript links, “#” or “javascript:void(0)”?

CSP

Posted by Reiphiel
JavaScript/jQuery2014. 8. 8. 07:30
반응형

 웹 개발을 진행하다 보면 유저 인터페이스 구성을 위해 마우스 휠에 의한 스크롤을 막아야 할 경우가 생긴다. 이럴경우 자바스크립트의 jquery를 이용하여 간단하게 제어할 수 있다. 아래의 소스 코드를 확인해보자.(※버튼을 이용해 직접 테스트 해볼 수 있다.)


<script type="text/javascript">
    $(document).on("mousewheel.disableScroll DOMMouseScroll.disableScroll touchmove.disableScroll", function(e) {
        e.preventDefault();
        return;
    });
    $(document).on("keydown.disableScroll", function(e) {
        var eventKeyArray = [32, 33, 34, 35, 36, 37, 38, 39, 40];
        for (var i = 0; i < eventKeyArray.length; i++) {
            if (e.keyCode === eventKeyArray [i]) {
                e.preventDefault();
                return;
            }
        }
    });
</script>



<script type="text/javascript">
     $(document).off(".disableScroll");
</script>




 상기에서 확인한 바와같이 jquery의 on/off 펑션을 이용하여 mousewheel, DOMMouseScroll, touchmove 이벤트 활성/비활성화 시키고 있다. jquery의 on/off 펑션에 대해서는 jquery의 api를 참고하면 될 듯 하다. 간단하게 설명하자면 .on(이벤트, 핸들러)의 형태로 호출하며 이벤트 파라메터의 경우 단일 혹은 공백문자 구분으로 복수지정이 가능하며 이벤트명 또는 이벤트명과 네임스페이스의 결합형태 로 지정할 수 있다. 위의 소스에서는 mousewheel이라는 이벤트명에 disableScroll이라는 네이스페이가 결합된 형태이다. 네임스페이스는 도트문자[.]로 구분하며 여러계층으로 지정이 가능하다. 해제 펑션의 경우 .off(이벤트)의 형태로 호출하며 이벤트 파라메터는 on과 마찬가지로 지정하면 된다. 제거시에는 위의 소스에서처럼 네임스페이스로 호출하게 되면 해당 네임스페이스 포함 하위 네임스페이스를 제거가 가능하므로 호출별로 별도로 이벤트 컨트롤이 가능하다.


 예제에서 DOMMouseScroll이벤트는 파이어폭스 계열에서는 mousewheel이벤트가 작동하지 않으므로 해당 이벤트로 DOMMouseScroll를 추가해 주어야 하며 touchmove는 태블릿 피시에서의 터치 이벤트에 관여한다. 별도로 호출하고 있는 keydown의 경우는 pageup등의 페이지를 스크롤할 수 있는 키의 이벤트에 관여하여 이벤트를 핸들링한다.



 위의 코드를 참고하면 페이지 스크롤을 일시적으로 블럭 시켰다가 다시 해제할 수 있으므로 UI구성시에 도움이 될듯 하다.


※IE7에서 동작하지 않는 케이스가 있어 http://www.quirksmode.org/dom/events/scroll.html 참고하여  이벤트 핸들링 을  window에서 document로 변경하였습니다.



'JavaScript > jQuery' 카테고리의 다른 글

checkbox 단일 선택  (1) 2014.01.11
jquery DOM 요소 이동  (0) 2013.12.29
Posted by Reiphiel
JavaScript/ajax2014. 6. 2. 15:14
반응형

 Internet Explorer8 또는 9 버전을 이용해서 웹 페이지를 작성하다 jquery의 ajax호출을 이용 화면의 구성요소를 호출할 경우아래와 같은 스크립트 에러로 인하여 화면의 일부 구성요소들이 로딩되지 않는 현상이 발생하는 경우가 있다.



 이 경우 ie의 경우 여타의 브라우저(Firefox, Chrome)처럼 상세한 에러 메시지를 발생시켜 주지 않아서 에러를 특정하고 배제하는데 생각외로 시간이 걸리는 경우가 있다. 이럴 경우 아래와 같은 부분을 후보로 올리고 에러를 특정해 보는 것이 유효할 듯 하다.


주요 원인

ajax를 이용하여 Javascript를 구문을 호출할 경우 구문 체크가 매우 엄격하게 일어나는 듯 하다.


적용 가능한 해결책 리스트


1. 자바스크립트 구문 에러

불러올 대상의 스크립트 요소 중 일부에서 스크립트 구문 오류가 있을 경우 위와 같은 에러를 만날 수 있다.

※필자의 경우는 아래처럼 스크립트의 텍스트 출력방지를 위한 주석 처리에 실수가 있었던 경우였다.(커맨트 열고 닫지 않았다. 초보적인 미스 ㅜㅜ)

<script type='text/javascript'>
//<!--
    /* 스크립트 구문 */
</script>


2. 여분의 콤마

아래처럼 배열의 마지막 요소 다음에 콤마가 남아 있는 경우가 있다. 로직상의 미스일 경우도 있고 프로그래밍의 편의상 남겨둔 경우도 있으나 상황에 따라 구문에러인 경우도 있고 정상적으로 동작하는 경우도 있으므로 여분의 콤마는 배제하여 일관적으로 동작할 수 있도록 하자.

<script type='text/javascript'>
var arr = ['item1','item2',];
</script>


3. 컨텐츠 타입 ie의 경우 ajax호출의 응답이 json인 경우 컨텐츠 타입을 application/json으로 지정하면 제대로 동작하지 않는 케이스가 있다. 이경우 text/plain으로 컨텐츠 타입을 지정하면 해결된다.


 

 위에서 열거한 케이스 이외에도 여러가지 케이스가 있을 수 있지만 위의 내용만 잘 고려해도 에러를 어느정도 방지할 수 있다고 생각된다.

'JavaScript > ajax' 카테고리의 다른 글

ajax get 한글 파라메터 깨지는 문제  (0) 2014.03.10
Posted by Reiphiel