HTML에서 onClick ()을 사용하는 것이 왜 나쁜 습관입니까?


133

onClick()시맨틱에는 좋지 않기 때문에 HTML에서 와 같은 JavaScript 이벤트를 사용 하는 것은 나쁜 습관 이라고 여러 번 들었습니다 . 단점은 무엇이며 다음 코드를 수정하는 방법을 알고 싶습니다.

<a href="#" onclick="popup('/map/', 300, 300, 'map'); return false;">link</a>


4
onlickc에는 아무런 문제가 없지만 href를 만들면 #자바 스크립트를 사용하지 않도록 선택한 모든 사람이 멈춰서 아무것도 할 수 없습니다. 좋은 사이트이지만 단순히 창을 여는 경우에는 "실제"링크를 제공하지 않는 것이 멍청합니다.
Marc B

2
그 링크를 확실히 읽으십시오. 그것은 의미론과 거의 관련이 없으며, 그 페이지와 관련된 모든 것들과 관련이 있습니다 :-)
morewry

새 탭에서 링크를 열려고하면 왜 잘못된 지에 대한 예가 표시됩니다.
Sebastien C.

2
<button>링크는 실제 리소스를 가리켜 야하므로 이어야 합니다. 그것은 더 의미 론적이며 스크린 리더 사용자에게는 더 명확합니다.
programmer5000

답변:


171

거슬리지 않는 Javascript 에 대해 이야기하고있을 것입니다 .

<a href="#" id="someLink">link</a>

중앙 자바 스크립트 파일의 논리는 다음과 같습니다.

$('#someLink').click(function(){
    popup('/map/', 300, 300, 'map'); 
    return false;
});

장점은

  • 동작 (자바 스크립트)과 프레젠테이션 (HTML)이 분리됨
  • 언어의 혼합 없음
  • 브라우저 간 문제를 대부분 처리 할 수있는 jQuery와 같은 자바 스크립트 프레임 워크를 사용하고 있습니다.
  • 코드 복제없이 한 번에 많은 HTML 요소에 동작을 추가 할 수 있습니다

30
몇 가지 장점을 나열했지만 단점은 무엇입니까? 파란 연기를 디버깅?
abelito

2
@abelito : 디버깅이 단점인지 확실하지 않습니다. 브라우저 디버깅 도구 내에서 JavaScript를 단계별로 실행할 수 있으므로 디버깅하는 것이 유리합니다. 코드가 인라인 인 경우 쉽게 할 수 있는지 확실하지 않습니다 onClick. 스크립트에 대해 원하는 경우 단위 테스트를 작성할 수도 있습니다. 이는 코드가 내부에 onClick있고 논리가 분리되어 있지 않은 것으로 가정합니다 . 나는 개인적으로 눈에 거슬리지 않는 JavaScript를 디버깅하는 데 아무런 문제가 없으며 JavaScript 코드 관리 및 테스트의 이점은 그것을 사용하지 않는 것보다 훨씬 큽니다.
Nope

45
@ François Wahl : 가장 큰 단점은 검색 가능성입니다. HTML을 보면 어떤 콜백이 첨부되어 있는지 알 수 없습니다.
Michael Borgwardt

1
@MichaelBorgwardt : 나는 그것이 불리하다는 점을 전적으로 귀하에게 동의합니다. 코드가 잘 구성되고 체계화되어 있다면 프로젝트에서 작업하거나 다른 사람의 코드베이스를 디버깅 할 때 큰 문제로 보지 않습니다. 일반적으로, 나는 당신에 동의하지만, 검색 가능성이 인라인 스크립트를 작성하는 좋은 이유, 코드 테스트 가능성 및 기능 / 동작 코드를 DOM에서 분리하는 기능과 같은 이점을 희생시키는 좋은 이유는 아닙니다. 인라인 코드가 나쁘고 작동하지 않는다고 말하는 것이 아닙니다. 테스트 가능성과 같은 것에 관심이 있는지 아닌지에 따라 절대적으로 훌륭합니다.
Nope

4
초보자와 함께이 토론에 대한 또 다른 요점 onclick은 요소 상호 작용과 효과 (함수 호출) 사이의 인과 관계를보다 명확하게 매핑하고인지 부하를 줄일 수 있습니다. 많은 교훈은 학습자들 addEventListener에게 더 어려운 아이디어 안에 더 많은 아이디어를 담고 있습니다. 또한 Riot 및 React와 같은 최근의 컴포넌트 기반 프레임 워크는이 onclick속성을 사용하며 분리해야하는 개념을 변경하고 있습니다. onclick이를 지원하는 컴포넌트 로 HTML 에서 컴포넌트로 전송 하는 것이 학습을위한보다 효과적인 "단계"프로세스 일 수 있습니다.
jmk2142

41

jQuery를 사용하는 경우 :

HTML :

 <a id="openMap" href="/map/">link</a>

JS :

$(document).ready(function() {
    $("#openMap").click(function(){
        popup('/map/', 300, 300, 'map');
        return false;
    });
});

이것은 여전히 ​​JS없이 작동하거나 사용자가 링크를 클릭하면 이점이 있습니다.

또한 다음과 같이 다시 작성하여 일반 팝업을 처리 할 수 ​​있습니다.

HTML :

 <a class="popup" href="/map/">link</a>

JS :

$(document).ready(function() {
    $(".popup").click(function(){
        popup($(this).attr("href"), 300, 300, 'map');
        return false;
    });
});

이렇게하면 팝업 클래스에 팝업을 제공하여 모든 링크에 팝업을 추가 할 수 있습니다.

이 아이디어는 다음과 같이 더 확장 될 수 있습니다.

HTML :

 <a class="popup" data-width="300" data-height="300" href="/map/">link</a>

JS :

$(document).ready(function() {
    $(".popup").click(function(){
        popup($(this).attr("href"), $(this).data('width'), $(this).data('height'), 'map');
        return false;
    });
});

이제 onclick 항목을 작성하지 않고도 전체 사이트에서 많은 팝업에 동일한 비트 코드를 사용할 수 있습니다! 재사용성에 대한 예!

또한 나중에 팝업이 나쁜 습관이고 (그것들입니다!) 라이트 박스 스타일의 모달 창으로 바꾸고 싶다면 다음과 같이 변경할 수 있습니다.

popup($(this).attr("href"), $(this).data('width'), $(this).data('height'), 'map');

myAmazingModalWindow($(this).attr("href"), $(this).data('width'), $(this).data('height'), 'map');

전체 사이트의 모든 팝업이 이제 완전히 다르게 작동합니다. 팝업에서 수행 할 작업을 결정하는 기능 감지를 수행하거나 사용자 기본 설정을 저장하여 허용 여부를 결정할 수도 있습니다. 인라인을 클릭하면 큰 복사 및 붙여 넣기 작업이 필요합니다.


4
JavaScript없이 작동 ?? jQuery입니다. 브라우저에서 Javascript를 활성화해야 작동합니까?
Thomas Shields

2
예, 그러나이 경우 링크는 JavaScript없이 작업을 수행하는 페이지로 리디렉션 될 수 있습니다.
ThiefMaster

12
링크는 자바 스크립트없이 작동합니다. 링크에 일반 href 속성이 어떻게 있는지 확인하십시오. 사용자에게 JavaScript가없는 경우 링크는 여전히 링크이며 사용자는 여전히 컨텐츠에 액세스 할 수 있습니다.
morewry

3
@Thomas Shields : 아니오, Javascript가없는 경우 링크가 여전히 / map / ... 링크로 이동합니다.
Robert

2
아 리치! 우리는이 멋진 솔루션에 대해 당신을 사랑합니다!
Nirmal

21

매우 큰 JavaScript 응용 프로그램으로 인해 프로그래머는 전역 범위를 오염시키지 않기 위해 더 많은 코드 캡슐화를 사용하고 있습니다. HTML 요소에서 onClick 조치에 함수를 사용하려면 전역 범위에 있어야합니다.

다음과 같은 JS 파일을 보았을 것입니다 ...

(function(){
    ...[some code]
}());

이들은 즉시 호출되는 함수 표현식 (IIFE)이며 그 안에 선언 된 함수는 내부 범위 내에 만 존재합니다.

function doSomething(){}IIFE 내에서 선언 한 경우 doSomething()HTML 페이지에서 요소의 onClick 조치를 수행하면 오류가 발생합니다.

반면에 해당 IIFE 내에서 해당 요소에 대한 eventListener를 작성 doSomething()하고 리스너가 click 이벤트를 감지 할 때 호출 하면 리스너로 인해 doSomething()IIFE의 범위를 공유하는 것이 좋습니다 .

코드가 최소한 인 웹 응용 프로그램의 경우에는 중요하지 않습니다. 그러나 유지 관리가 가능한 큰 코드베이스를 작성하려는 경우 onclick=""피해야 할 습관입니다.


1
유지 관리가 가능한 큰 코드베이스를 작성하고자하는 경우 Angular, Vue, React와 같은 JS 프레임 워크를 사용합니다. HTML 프레임 워크 내에 이벤트 핸들러를 바인딩하는 것이 좋습니다.
Kamil Kiełczewski

20

여러 가지 이유로 좋지 않습니다.

  • 코드와 마크 업을 혼합
  • 이 방법으로 작성된 코드는 통과 eval
  • 그리고 글로벌 범위에서 실행

가장 간단한 방법은 요소에 name속성 을 추가하는 것입니다 <a>.

document.myelement.onclick = function() {
    window.popup('/map/', 300, 300, 'map');
    return false;
};

현대적인 모범 사례는 id이름 대신 대신 을 사용하는 것이지만 여러 기능을 단일 이벤트에 바인딩 할 수 있기 때문에 addEventListener()대신 사용하는 것이 좋습니다 onclick.


이 방법을 제안하더라도 이벤트 핸들러 충돌과 관련된 많은 문제가 발생합니다.
preaction

3
@preaction은 인라인 이벤트 핸들러와 마찬가지로 왜 대답이을 사용하는 것이 더 낫고 왜 그런지 대답합니다 addEventListener().
Alnitak

2
누군가 이것을 더 설명 할 수 있습니까? "이런 방식으로 작성된 코드는 평가를 거칩니다"... 웹에서 이것에 대해 아무것도 찾지 못했습니다. 인라인 Javascript를 사용하면 성능이나 보안상의 단점이 있다고 말씀하십니까?
MarsAndBack

12

몇 가지 이유가 있습니다.

  1. HTML과 클라이언트 쪽 스크립트와 같이 마크 업을 분리하는 것이 유지 관리에 도움이된다는 것을 알았습니다. 예를 들어 jQuery를 사용하면 프로그래밍 방식으로 이벤트 핸들러를 쉽게 추가 할 수 있습니다.

  2. 제공하는 예제는 자바 스크립트를 지원하지 않거나 자바 스크립트가 꺼져있는 모든 사용자 에이전트에서 중단됩니다. 점진적 향상 의 개념은 /map/자바 스크립트가없는 사용자 에이전트 에 대한 간단한 하이퍼 링크를 장려 한 다음 자바 스크립트를 지원하는 사용자 에이전트에 대해 클릭 핸들러를 문법적으로 추가하는 것입니다.

예를 들면 다음과 같습니다.

마크 업 :

<a id="example" href="/map/">link</a>

자바 스크립트 :

$(document).ready(function(){

    $("#example").click(function(){
        popup('/map/', 300, 300, 'map');
        return false;
    });

})

2
점진적인 향상을 상기시켜 주셔서 감사합니다. 그리고 이것은 여전히 ​​그 패러다임에도 맞습니다 :<a href="https://stackoverflow.com/map/" onclick="popup('/map/', 300, 300, 'map'); return false;">link</a>
Daniel Sokolowski

10

개정

에 잘 띄지 않는 JavaScript 접근 방식은 PAST에서 우수했습니다. 특히 HTML의 이벤트 핸들러 바인드는 나쁜 습관으로 간주되었습니다 (주로 YiddishNinjaonclick events run in the global scope and may cause unexpected error 가 언급 한 내용 )

하나...

현재이 접근법은 약간 구식이며 업데이트가 필요한 것 같습니다. 누군가가 전문 프론트 엔드 개발자가되고 크고 복잡한 응용 프로그램을 작성하려면 Angular, Vue.js 등과 같은 프레임 워크를 사용해야합니다. 그러나 프레임 워크는 일반적으로 이벤트 핸들러가 바인딩되는 HTML 템플릿 을 사용하거나 사용하도록 허용합니다. html 템플릿 코드에서 직접 사용하면 매우 편리하고 명확하며 효과적입니다. 예를 들어 각도 템플릿에서는 일반적으로 사람들이 작성합니다.

<button (click)="someAction()">Click Me</button> 

원시 js / html에서 이와 동등한 것은

<button onclick="someAction()">Click Me</button>

차이점은 원시 js onclick이벤트가 전역 범위에서 실행 된다는 것입니다 . 그러나 프레임 워크는 캡슐화를 제공합니다.

문제가 어디에 있습니까?

문제는 항상 html-onclick이 나쁘고 항상 사용하는 초보자 프로그래머 btn.addEventListener("onclick", ... )가 템플릿이있는 일부 프레임 워크를 사용 하려고 할 때 ( 결점addEventListener 이 있습니다 -DOM 을 동적으로 사용하여 DOM을 업데이트하면 innerHTML=(꽤 빠릅니다 ) 이벤트를 느슨하게합니다) 핸들러는 그런 식으로 바인딩됩니다). 그런 다음 프레임 워크 사용법에 대한 나쁜 습관이나 잘못된 접근 방식에 직면하게됩니다. 프레임 워크를 주로 사용하지 않고 템플릿 부분에 초점을 맞추지 않기 때문에 프레임 워크를 매우 나쁜 방식으로 사용합니다. 암호). 이 습관을 바꾸려면 많은 시간을 잃게 될 것입니다 (아마도 행운과 선생님이 필요할 것입니다).

제 생각에는 제 학생들과의 경험을 바탕으로 처음에 html-handlers-bind를 사용하면 더 좋습니다. 내가 말했듯이 핸들러는 글로벌 범위에서 호출되는 것이 사실이지만이 단계 학생들은 일반적으로 제어하기 쉬운 작은 응용 프로그램을 만듭니다. 더 큰 응용 프로그램을 작성하려면 일부 프레임 워크를 선택합니다.

그래서 뭘 할건데?

Unobtrusive JavaScript 접근 방식을 업데이트하고 html에서 바인드 이벤트 핸들러 (결국 간단한 매개 변수로)를 허용 할 수 있습니다 (그러나 바인드 핸들러 만-OP 쿼리와 같이 onclick에 로직을 넣지 않음). 원시 js / html에 대한 제 의견으로는 이것이 허용되어야합니다.

<button onclick="someAction(3)">Click Me</button>

또는

그러나 아래 예는 허용되지 않아야합니다.

<button onclick="console.log('xx'); someAction(); return true">Click Me</button>

<a href="#" onclick="popup('/map/', 300, 300, 'map'); return false;">link</a>

현실은 변하고 우리의 관점도


안녕하세요 Kamil, 저는 JavaScript 초보자이며 onclick 사용에 혼란을 겪었습니다. 즉, 다음과 같이 onclick의 단점을 설명 할 수 있습니다. 1. 하나의 인라인 이벤트 만 할당 할 수 있습니다. 인라인 이벤트는 DOM 요소의 속성으로 저장되며 모든 객체 속성과 마찬가지로 덮어 쓸 수 있습니다. 3. onclick 속성을 삭제하더라도이 이벤트는 계속 발생합니다.
mirzhal

1
Ad 1. 그렇습니다. 그러나 내 경험 (각도)은 이것이 대부분의 상황에서 충분하다는 것을 보여줍니다 addEventListener. Ad 2. 그렇습니다. 그것들은 덮어 쓸 수 있습니다 (그러나 보통 아무도하지 않습니다)-문제는 어디에 있습니까? 광고 3. 핸들러는 삭제 onclick을 ATTRIB 후 해고되지는 않습니다 - 증거 여기
카밀 Kiełczewski을

8

그것은 A의 "라는 패러다임 겸손한 자바 스크립트 ". 현재의 "웹 표준"은 기능과 표현을 분리한다고 말합니다.

실제로는 "나쁜 습관"이 아니며 대부분의 새로운 표준에서는 인라인 JavaScript 대신 이벤트 리스너를 사용하기를 원합니다.

또한 이것은 개인적인 일 일 수도 있지만 이벤트 리스너를 사용할 때, 특히 실행하려는 JavaScript 문이 두 개 이상인 경우 훨씬 쉽게 읽을 수 있다고 생각합니다.


2
해당 주제의 Wikipedia 페이지가 4 세 이상입니다. 더 이상 새로운 패러다임 이 아닙니다 . :)
Quentin

@David : "새롭지"않을 수도 있지만 아직 사용하지 않는 사람들이 있으므로 "새"입니다.
로켓 Hazmat

6

귀하의 질문은 내가 생각하는 토론을 유발할 것입니다. 일반적인 생각은 행동과 구조를 분리하는 것이 좋다는 것입니다. 또한 인라인 클릭 핸들러 인 afaik eval은 실제 자바 스크립트 함수가되어야합니다. 그리고 그것은 꽤 구식이지만, 그것은 꽤 흔들리는 주장입니다. 아, 잘 읽어 보세요 @ quirksmode.org


나는 다시 한번 거룩한 전쟁을 만들고 싶지 않다. 나는 진실을 찾으려고 노력하고있다 : \
NiLL

2
  • onclick 이벤트는 전체 범위에서 실행되며 예기치 않은 오류가 발생할 수 있습니다.
  • 많은 DOM 요소에 onclick 이벤트를 추가하면
    성능과 효율성 이 저하됩니다 .

0

인라인 핸들러를 사용하지 않는 두 가지 이유 :

지루한 견적 이스케이프 문제가 필요할 수 있습니다.

감안할 때 임의의 사용자가 일반 솔루션, 해당 문자열이있는 함수를 호출하는 인라인 핸들러를 구성 할 수 있도록하려면, 문자열을, 당신은 탈출해야합니다 속성 (관련 HTML 엔티티와) 구분 기호를, 그리고 당신은거야 다음과 같이 속성 내부의 문자열에 사용되는 구분 기호를 이스케이프 처리해야합니다.

const str = prompt('What string to display on click?', 'foo\'"bar');
const escapedStr = str
  // since the attribute value is going to be using " delimiters,
  // replace "s with their corresponding HTML entity:
  .replace(/"/g, '&quot;')
  // since the string literal inside the attribute is going to delimited with 's,
  // escape 's:
  .replace(/'/g, "\\'");
  
document.body.insertAdjacentHTML(
  'beforeend',
  '<button onclick="alert(\'' + escapedStr + '\')">click</button>'
);

그건 매우 추한. 위의 예에서 's 를 바꾸지 alert('foo'"bar')않으면 유효한 구문이 아니기 때문에 SyntaxError가 발생 합니다. "s 를 바꾸지 않으면 브라우저는이 onclick"s로 구분 된 속성 의 끝으로 해석 하며 이는 잘못된 것입니다.

하나가 습관적으로 인라인 처리기를 사용하는 경우, 하나는 위와 비슷한 일을 기억해야합니다 (그것을해야 할 것이다 우측 ) 마다 한 눈에 이해하기 지루하고 어렵다. 임의의 문자열을 간단한 클로저에 사용할 수 있도록 인라인 핸들러를 완전히 피하는 것이 좋습니다.

const str = prompt('What string to display on click?', 'foo\'"bar');
const button = document.body.appendChild(document.createElement('button'));
button.textContent = 'click';
button.onclick = () => alert(str);

그렇게 좋지 않습니까?


인라인 핸들러의 스코프 체인은 매우 독특합니다.

다음 코드가 무엇을 기록 할 것이라고 생각하십니까?

let disabled = true;
<form>
  <button onclick="console.log(disabled);">click</button>
</form>

사용해보십시오. 스 니펫을 실행하십시오. 아마 당신이 기대했던 것이 아닙니다. 왜 그렇게 하는가? 인라인 핸들러는 with블록 내부에서 실행되기 때문 입니다. 위의 코드는 세 개의 with 블록 안에 있습니다 . 하나는 document, 하나 <form><button>:

여기에 이미지 설명을 입력하십시오

이후 disabled버튼의 속성은, 참조하는 disabled인라인 처리기 내부하는 버튼의 속성이 아니라 외측 지칭 disabled변수. 이것은 매우 직관적입니다. with많은 문제가 있습니다 : 혼란스러운 버그의 원인이 될 수 있으며 코드 속도가 크게 느려집니다. 엄격 모드에서는 전혀 허용되지 않습니다. 그러나 인라인 핸들러를 사용하면 하나 뿐 아니라 여러 개의 중첩을 통해 코드를 실행 해야 합니다 . 미쳤어withwithwith

with코드에서 절대 사용해서는 안됩니다. 인라인 핸들러 with는 모든 혼란스러운 동작과 함 2 암시 적으로 필요하므로 인라인 핸들러도 피해야합니다.

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