简体   繁体   中英

Abstracting repetitive addEventListener('click'… functions to optimize code

EDIT: Looking for a non-Jquery Answer

As it stands this code is incredibly long for how simple it is. The only difference between specific instances is a number indicating the ID of the target. Is there a way to accomplish the same result with a single function that gets fed variable based on which div is clicked?

var $ = Sizzle,
p0 = $("#p0")[0];
p1 = $("#p1")[0];
p2 = $("#p2")[0];
p3 = $("#p3")[0];
p4 = $("#p4")[0];
p5 = $("#p5")[0];
p6 = $("#p6")[0];
p7 = $("#p7")[0];
lp0 = $("#productMenu li")[0];
lp1 = $("#productMenu li")[1];
lp2 = $("#productMenu li")[2];
lp3 = $("#productMenu li")[3];
lp4 = $("#productMenu li")[4];
lp5 = $("#productMenu li")[5];
lp6 = $("#productMenu li")[6];
lp7 = $("#productMenu li")[7];


lp0.addEventListener('click',open0,false);
lp1.addEventListener('click',open1,false);
lp2.addEventListener('click',open2,false);
lp3.addEventListener('click',open3,false);
lp4.addEventListener('click',open4,false);
lp5.addEventListener('click',open5,false);
lp6.addEventListener('click',open6,false);
lp7.addEventListener('click',open7,false);



function open0(){
p0.classList.toggle('off');
}

function open1(){
p1.classList.toggle('off');
}
function open2(){
p2.classList.toggle('off');
}

function open3(){
p3.classList.toggle('off');
}
function open4(){
p4.classList.toggle('off');
}

function open5(){
p5.classList.toggle('off');
}
function open6(){
p6.classList.toggle('off');
}

function open7(){
p7.classList.toggle('off');
}

You can try this code:

$('#productMenu li').on('click', function () {
  var index = $("#productMenu li").index($(this));
  $('#p' + index).toggleClass('off');
});

In plain script, something like the following should work:

// Helper to convert a list to an array
function toArray(list) {
  var array = [];
  for (var i=0, iLen=list.length; i<iLen; i++) {
    array[i] = list[i];
  }
  return array;
}

// Helper to add a listener without closure
function addFunction(source, target) {
  source.addEventListener('click', function(){target.classList.toggle('off')}, false);  
}

function addListeners() {
  var nodes = [];

  for (var i=0; i<8; i++) {
    pNodes.push(document.getElementById('p' + i));
  }

  var lpNodes = toArray(document.getElementById('productMenu').getElementsByTagName('li'));

  for (var j=0, jLen=lpNodes.length; j<jLen; j++) {
    addFunction(lpNodes[j],pNodes[j]); 
  }
}

Untested of course, but the approach should help. It isn't really necessary to convert the NodeList returned by getElementsByTagName to an array, but it may be help performance.

There are other approaches to this, most obviously to use event delegation and put a single listener on a parent element (an UL?) that sees where the click came from, then toggles the related element if required. eg if the click came from lp0, toggle p0 (though you should probaby be using classes for this, not IDs).

Something like:

function handleClick(event) {
  var element;
  var target = event.target;

  if (target.tagName && target.tagName.toLowerCase() == 'li') {
    var id = target.id.match(/\d+/$);

    if (id) {
      element = document.getElementById('p' + id[0]);
    }

    if (element) {
      element.classList.toggle('off');
    }
  }
}

window.onload = function() {
  document.getElementById('productMenu').addEventListener('click', handleClick, false);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM