2014-12-23 2 views
4

내 페이지에서 jquery를 제거하고 일부 기능을 순수 js로 다시 쓰려고 시도하고 있습니다. 몇 가지 li 요소가 포함 된 두 개의 클래스 작업 목록이 있습니다. 각 li 요소에는 '활성'클래스를 추가하기 위해 클릭시 동작이 있어야합니다. JQuery와 그것은 매우 간단합니다 : 여러 자식 요소에 수신기 연결

$('.work li').on('click', function() { 
      var that = $(this); 
      that.parent().find('li.active').removeClass('active'); 
      $(this).addClass('active'); 
     }) 

인가가 아니라 중첩 루프와 같은 것을 만드는 것보다 순수 JS에서 더 좋은 솔루션 : 당신은 실제로 래퍼 요소에 이벤트 리스너를 클릭하여 첨부 할 수

var lists = document.getElementsByClassName('work'); 
    for(var i=0; i<lists.length; i++){ 
     var children = lists[i].querySelectorAll('li'); 
     for(var j=0; j<children.length;j++){ 
     children[j].addEventListener(); 
     } 
    } 
+0

이제 JQuery가 개발되어 인기가있는 이유를 알 수 있습니다. – jalynn2

+0

이제는 js에 대해 얼마나 모르는 지 알 수 있습니다. – mjanisz1

+0

DOM을 직접 사용하면 지루하고 많은 검색 루프가 필요합니다. 또한 메소드 이름과 기능에 대해 브라우저 간에는 몇 가지 차이점이 있습니다. 그것들은 처음에는 jQuery가 해결하고자하는 두 가지 문제였습니다. 왜 그것을 제거하려고합니까? – jalynn2

답변

2

몇 가지 li 요소가 포함 된 두 개의 클래스 작업 목록이 있습니다. 각각의 li 요소에는 '활성'클래스를 추가하기 위해 클릭시 조치가 있어야합니다.

querySelectorAll에 의해 반환 된 모든 li에 이벤트 수신기를 추가하여 전체 기능을 만들 수 있습니다. querySelectorAll은 배열이 아닌 nodeList를 반환하므로 반복 할 수 있도록 매핑해야합니다. 그러나 우리는 여전히 세트를 반복하고 있음에 유의하십시오.

예 발췌문 : 당신은 또한 처리 할 event.target를 사용하여 다음 이벤트 위임을 사용 만 ul에 이벤트 리스너를 추가 할 수 사실

var lists = document.querySelectorAll(".work li"), 
 
    doSomething = function() { 
 
     [].map.call(lists, function(elem) { elem.classList.remove("active") }); 
 
     this.classList.add("active"); 
 
    }; 
 
[].map.call(lists, function(elem) { 
 
    elem.addEventListener("click", doSomething, false); 
 
});
li { cursor: pointer; } 
 
.active { background-color: yellow; }
<ul class="work"><li>One</li><li>Two</li><li>Three</li></ul> 
 
<ul class="work"><li>Four</li><li>Five</li><li>Six</li></ul>


너의 일과. 이것은 각각의 경우에 각각 li에 이벤트 리스너를 추가하는 것보다 낫습니다. ul과 같은 핸들러 만있을 것입니다.


오히려 중첩 루프

별로

와 같은 것을 만드는 것보다 순수 JS에서 더 좋은 솔루션이있다. 어쨌든 요소 세트를 반복해야합니다. 재즈의 측면에서 더 멋지 네요. 루프를 피하는면에서는 더 멋지지만, 그렇지 않습니다. 효율성 측면에서 더 좋았지 만 그렇습니다. 위의 바닐라 자바 ​​스크립트 코드를 질문의 jQuery 코드와 비교하십시오.

+1

! 이것은 깔끔한 해결책처럼 보입니다! 나는 또한 요소 집합을 지나는 [] .map.call을 좋아한다! – mjanisz1

3

은 필터를 클릭하여 li 요소를 event.target (또는 event.srcElement의 경우)을 사용하여 필터링합니다.

아래 코드를 사용해보십시오 (프로덕션 코드가 아닌 브라우저 호환성을 위해 특히 향상되어야 함). 이 솔루션의 좋은면은 ... 동적으로 래퍼 요소에 추가 된 새로운 요소를 감시하지 않도록

function clickHandler(e) { 
 
    var elem, evt = e ? e : event; 
 
    if (evt.srcElement) { 
 
    elem = evt.srcElement; 
 
    } else if (evt.target) { 
 
    elem = evt.target; 
 
    } 
 

 
    // Filter out li tags 
 
    if (elem && ('LI' !== elem.tagName.toUpperCase())) { 
 
    return true; 
 
    } 
 

 
    console.log('You clicked: ' + elem.innerHTML) 
 
    return true; 
 
} 
 

 
var lists = document.getElementsByClassName('work'); 
 
for (var i = 0; i < lists.length; i++) { 
 
    var children = lists[i].addEventListener('click', clickHandler); 
 
}
<ul class="work"> 
 
    <li>1.1</li> 
 
    <li>1.2</li> 
 
    <li>1.3</li> 
 
    <li>1.4</li> 
 
</ul> 
 
<ul class="work"> 
 
    <li>2.1</li> 
 
    <li>2.2</li> 
 
    <li>2.3</li> 
 
    <li>2.4</li> 
 
</ul> 
 
<ul class="work"> 
 
    <li>3.1</li> 
 
    <li>3.2</li> 
 
    <li>3.3</li> 
 
    <li>3.4</li> 
 
</ul>

2

입니다. 왜 document.querySelectorAll을 더 잘 사용하지 않는 것이 좋을까요? 그것은 css의 문법을 사용하기 때문에 우리는 한 번에 둘 다 얻을 수 있습니다. 이 같은

아마 뭔가 :

{ 
liList = document.querySelectorAll('.work li'); 
var i, n = liList.length; 
for (i=0; i<n; i++) 
    liList[i].addEventListener(eventName, functionName, useCapture); 
} 
+0

이것은 내게 가장 깨끗한 것 – SuperUberDuper

2

querySelectorAll()는 매우 강력한 도구입니다.

나는 JSFiddle을 만들었습니다.

코드는 여전히 충분히 좋은 읽을 수 있습니다 :

for (var item of document.querySelectorAll(".work li")) { 
item.addEventListener("click", function (evt) { 
    evt.target.classList.add("active"); 
}, false); 
} 

또 다른 방법은 (당신은 여전히 ​​대해 forEach를 사용하여 반복 할 경우)입니다 : 여기

Array.prototype.forEach.call(document.querySelectorAll(".work li"), function(item) { 
    item.addEventListener("click", function (evt) { 
     evt.target.classList.add("active"); 
    }, false); 
}); 

(JSFiddle) 우리는을 통해 interating된다 NodeListquerySelectorAll(".work li")에 의해 calling에 의해 Array.prototype.forEach 방법으로 반환했습니다.

그리고 여기 (Jsfiddle는) 클래스 전환 전체 예입니다 :

Array.prototype.forEach.call(document.querySelectorAll(".work li"), function(item) { 
    item.addEventListener("click", function (evt) { 
     evt.target.toggleActive = !evt.target.toggleActive; 
     evt.target.classList[!!evt.target.toggleActive ? 'add' : 'remove']("active"); 
    }, false); 
}); 

과 마지막 시간 (Jsfiddle)에서 하나의 활성 요소가 있어야하는 경우 :

var currentActiveElement; 
Array.prototype.forEach.call(document.querySelectorAll('.work li'), function(item) { 
item.addEventListener('click', function(evt) { 
    currentActiveElement && currentActiveElement.classList.remove('active'); 
    currentActiveElement = evt.target; 
    currentActiveElement.classList.add('active'); 
}, false); 
}); 
+0

우리는 어떻게 할 수 있지만 각각에 대한 querySelectorAll에 대한 사용하지 않을까? – SuperUberDuper

+2

질문을 올바르게 이해하면. 'querySelectorAll()'객체 [NodeList] (https://developer.mozilla.org/en-US/docs/Web/API/NodeList), 마녀 [배열과 똑같이 처리 할 수 ​​없음] (https : //developer.mozilla.org/en-US/docs/Web/API/NodeList#Why_is_NodeList_not_an_Array.3F). –

+0

멋진 감사 !!!!!! 덕분에 – SuperUberDuper

1

사람들은 고유 한 DOM 방법을 사용하는 것에 대해 불평하지만 전략적으로 배치 된 설탕으로는 도움이되지 않는다. 그것을 당신이 원하는 방법을 작성하여 시작 :

eachClass('work', function(work) { 
    eachSelector(work, 'li', function(li) { 
     on(li, 'click', function() { 
      eachChild(parent(li), active.remove); 
      active.add(li); 
     }); 
    }); 
}); 

지금 당신은 단지 다음과 같은 eachClass, eachSelector, eachChild, parenton, 뭔가를 작성해야합니다. 그들은 각각 약 2-3 라인이 될 것입니다. 한 번 쓰는 것만으로도 충분합니다. 작은 도서관이 있습니다.

function eachClass(cls, fn) { 
    [].forEach.call(document.getElementsByClassName(cls), fn); 
} 

active은 무엇입니까? 특정 클래스를 설정하고 제거하기 위해 만들 수있는 작은 객체입니다.

등등. 훌륭한 프로그래머들은 계속해서 작은 프레임 워크와 계층, 유틸리티 및 미니 언어를 꾸준히 구축하고 있습니다. 이것이 코드를 간결하고 읽기 쉽고 버그가 덜 생기고 작성하기 쉽도록 만드는 이유입니다.

관련 문제