How can I improve this component with using event delegation rather than doing a lookup using parentNode
so that I can change the markup around without having to update the JavaScript?
HTML
<div class="drop-down-wrapper"> <div class="drop-down-btn-wrapper"> <div class="drop-down-open"><img src="http://placehold.it/175x35" /></div> <div class="drop-down-closed"><img src="http://placehold.it/150x35" /></div> </div> <div class="drop-down-content js-drop-down"> <div class="content-wrapper"> <p> Lorem ipsum dolor sit amet, consectetuer adipiscing elit </p> </div> </div> </div>
JavaScript
(function(){ var dropDownClosed = 'js-drop-down', dropDownButtonList = document.querySelectorAll('.drop-down-btn-wrapper'); function init() { for(var i=0; i<dropDownButtonList.length; i++) { dropDownButtonList[i].addEventListener('click', initDropdown, false); } } function initDropdown(e) { var event = e.target; var contentWrapper = event.parentNode.parentNode.parentNode.childNodes[3]; var content = event.parentNode.parentNode.parentNode.childNodes[3].childNodes[1]; var closedButton = event.parentNode.parentNode.parentNode.childNodes[1].childNodes[3]; var contentHeight = content.offsetHeight; if(hasClass(contentWrapper, dropDownClosed)) { removeClass(contentWrapper, dropDownClosed); contentWrapper.style.height = contentHeight+'px'; closedButton.style.opacity = '0.0'; } else { addClass(contentWrapper, dropDownClosed); contentWrapper.style.height = 0+'px'; closedButton.style.opacity = '1.0'; } } function hasClass(ele, cls) { return ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)')); } function addClass(ele, cls) { if (!hasClass(ele, cls)) ele.className += " " + cls; } function removeClass(ele, cls) { if (hasClass(ele, cls)) { var reg = new RegExp('(\\s|^)' + cls + '(\\s|$)'); ele.className = ele.className.replace(reg, ''); } } init(); }());
CSS
.drop-down-wrapper { position:relative; border: 2px black solid; margin-bottom:20px; padding:20px 0; } .content-wrapper { padding:15px; margin:30px 0; } .drop-down-open { position:absolute; top:0; border: thin red solid; } .drop-down-closed { position:absolute; top:0; border: 2px solid green; } .drop-down-content { background-color:#fff; overflow:hidden; height:0; }