2010-05-26 49 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

相關問題