2010-05-26 60 views
1

我写了一个项目,下面的代码,我的工作:如何重构此JavaScript代码以避免在循环中生成函数?

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属性值(例如“相关搜索”)和相应的描述(例如“相关搜索”);
  • 对于每个内部数组,找到document中的元素以及相应的id属性,然后收集其中所有元素(超链接)的集合;
  • 遍历该集合并附加onclick处理程序每​​个超链接,这应该调用clicky.log,传递作为参数的对应于id(例如,“相关搜索”为id“相关的搜索”)的描述和被点击的<a>元素的href属性的值。

希望这不是完全混淆!代码可能比这更明显。

我相信,我在这里实行的是封闭的,但JSLint的抱怨:

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

所以,我的问题是:

  • 我如何重构这个代码,以JSLint是否合适?或者,更好的是,有没有一种最佳实践方式可以做到这一点,而不管JSLint认为什么?
  • 我应该依靠事件委派吗?也就是说,将onclick事件处理程序附加到document元素中,id属性位于我的阵列中,然后查看event.target?我以前曾经这样做过,理解这个理论,但是我对这些细节很朦胧,并且希望得到一些关于什么样的指导 - 假设这是一种可行的方法。

非常感谢您的帮助!

回答

1

代表团是一个更好的办法。 JSLint抱怨,因为你每次在循环内创建一个新的函数。但是,我并不是在文档上设置单个事件来监听所有点击事件,而是在所有具有id分配给它们的单独根元素上设置处理程序。单个处理程序可以重用于所有这些元素。

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' 
}; 
+0

谢谢,Anurag!对此,我真的非常感激。这看起来不错。 – Bungle 2010-05-26 07:09:52

+0

谢谢@Bungle。很高兴你发现它有帮助。干杯! – Anurag 2010-05-26 07:27:09

1

此代码不能很好维护!我讨厌搡jQuery的了你的喉咙,但是这看起来像一个情况是会非常有用的你,是这样的:

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

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

您可以通过添加类“可追踪”到每一个环节实现跟踪和地图链接查找表通过使用例如$(this).attr('rel')。

希望是有道理的。

+0

谢谢,詹姆斯!这是有道理的,我很欣赏答案和你的方法。不幸的是,我绝对不能在这个项目上使用jQuery - 它被部署在一个非常高流量的环境中,甚至24KB的jQuery也太多了。 – Bungle 2010-05-26 07:06:48

+0

即使从例如谷歌CDN使用jQuery?所以你实际上减少了你的外出流量,因为少了js ...?只是一个想法:D – 2010-05-26 09:16:27

1

您可以创建一个函数来构建事件处理程序,例如,:

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); 
    } 
} 

我也觉得event delegation也是一个非常不错的选择,你可以很容易实现:

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 
} 
​ 
+0

非常感谢,CMS!我希望我能接受你的答案和Anurag的,但他们都很棒,而且他在第一时间只有几分钟。 FWIW,这对我非常有帮助。 – Bungle 2010-05-26 07:09:14

相关问题