Как я могу реорганизовать этот код JavaScript, чтобы избежать создания функций в цикле? - PullRequest
1 голос
/ 26 мая 2010

Я написал следующий код для проекта, над которым я работаю:

var clicky_tracking = [
  ['related-searches', 'Related Searches'],
  ['related-stories', 'Related Stories'],
  ['more-videos', 'More Videos'],
  ['web-headlines', 'Publication']
];

for (var x = 0, length_x = clicky_tracking.length; x < length_x; x++) {
  links = document.getElementById(clicky_tracking[x][0])
                  .getElementsByTagName('a');
  for (var y = 0, length_y = links.length; y < length_y; y++) {
    links[y].onclick = (function(name, url) {
      return function() {
        clicky.log(url, name, 'outbound');
      };
    }(clicky_tracking[x][1], links[y].href));
  }
}

Я пытаюсь сделать следующее:

  • определяет двумерный массив, причем каждый экземпляр содержит внутренние массивы, содержащие два элемента: значение атрибута id (например, «related-search») и соответствующее описание (например, «Related Searches»);
  • для каждого из внутренних массивов, найдите элемент в document с соответствующим атрибутом id, а затем соберите в нем коллекцию всех <a> элементов (гиперссылок);
  • перебирает эту коллекцию и прикрепляет обработчик onclick к каждой гиперссылке, которая должна вызывать clicky.log, передавая в качестве параметров описание, соответствующее id (например, «Связанные поиски» для id «related-search») и значение атрибута href для элемента <a>, по которому был выполнен щелчок.

Надеюсь, это не совсем сбивало с толку! Код может быть более понятным, чем этот.

Я считаю, что то, что я реализовал здесь, является закрытием, но JSLint жалуется:

http://img.skitch.com/20100526-k1trfr6tpj64iamm8r4jf5rbru.png

Итак, мои вопросы:

  • Как я могу изменить этот код, чтобы сделать JSLint приемлемым? Или, что еще лучше, есть ли лучший способ сделать это, которого мне не хватает, независимо от того, что думает JSLint?
  • Стоит ли вместо этого полагаться на делегирование событий? То есть присоединение обработчиков событий onclick к элементам document с атрибутами id в моих массивах, а затем просмотр event.target? Я уже делал это раньше и понимаю теорию, но я очень туманный в деталях и был бы признателен за некоторые рекомендации о том, как это будет выглядеть - при условии, что это жизнеспособный подход.

Большое спасибо за любую помощь!

Ответы [ 3 ]

1 голос
/ 26 мая 2010

Вы можете создать функцию для создания обработчиков событий, например ::

function createClickHandler(url, name) {
  return function () {
    clicky.log(url, name, 'outbound');
  };
}

for (var x = 0, length_x = clicky_tracking.length; x < length_x; x++) {
  links = document.getElementById(clicky_tracking[x][0]) // NOTE:links should be 
                  .getElementsByTagName('a');            // declared at the top
  for (var y = 0, length_y = links.length; y < length_y; y++) {
    links[y].onclick = createClickHandler(clicky_tracking[x][1], links[y].href);
  }
}

Я также считаю, что делегирование событий также является действительно хорошим вариантом, вы можете реализовать его очень легко:

var clicky_tracking = [
  ['related-searches', 'Related Searches']
  //...
], elem;

function createClickHandler(name) { // capture only the 'name' variable
  return function (e) {
    e = e || window.event; // cross-browser way to get the event object
    var target = e.target || e.srcElement; // and the event target

    if (target.nodeName == "A") { // make sure that the target is an anchor
      clicky.log(target.href, name, 'outbound');
    }
  };
}

for (var x = 0, len = clicky_tracking.length; x < len; x++) {
  elem = document.getElementById(clicky_tracking[x][0]); // find parent element
  elem.onclick = createClickHandler(clicky_tracking[x][1]); // bind the event
}
​
1 голос
/ 26 мая 2010

Делегация - лучший подход. JSLint жалуется, потому что вы создаете новую функцию каждый раз в цикле. Однако вместо того, чтобы настраивать одно событие в документе для прослушивания всех событий щелчка, я бы предпочел настроить обработчик для всех отдельных корневых элементов, которым назначены идентификаторы. Один обработчик может быть повторно использован для всех этих элементов.

function logClick(event) {
    event = event || window.event;
    var link = event.target || event.srcElement;

    if(link.nodeName.toLowerCase() !== "a") {
        return;
    }

    var name = clicky_tracking[this.id];
    clicky.log(link.href, name, 'outbound');
}

Зарегистрируйте вышеуказанный обработчик с каждым корневым элементом.

for(var id in clicky_tracking) {
    var root = document.getElementById(id);
    root.onclick = logClick;
}

Также, чтобы избежать поиска по массиву, я изменил clicky_tracking с массива на объект для более легкого доступа по ключу.

var clicky_tracking = {
  'related-searches': 'Related Searches',
  'related-stories': 'Related Stories',
  'more-videos': 'More Videos',
  'web-headlines': 'Publication'
};
1 голос
/ 26 мая 2010

Этот код не очень удобен в обслуживании! Я ненавижу пихать jQuery в горло, но это выглядит как ситуация, где это было бы очень полезно для вас, что-то вроде:

$('a.trackable').click(function(e) {

  clicky.log(url, name, 'outbound');
};

Вы можете включить отслеживание, добавив класс «отслеживаемый» к каждой ссылке и сопоставив ссылки с таблицей поиска, используя, например, $ (this) .attr ('rel').

Надеюсь, что это имеет смысл.

...