2012-08-05 38 views
3

我在嘗試刪除重複的JavaScript代碼。我有一個頁面有很多<input type="file">。每個加載一個圖像並執行一些獨特的處理。問題是,我有以下代碼的很多重複:如何刪除DOM事件處理程序的重複JavaScript代碼?

inputFile1.onchange = function (e) { 
     var file = e.target.files[0]; 
     if (typeof file == 'undefined' || file == null) { 
      return; 
     } 
     var imageType = /image.*/; 
     if (!file.type.match(imageType)) { 
      window.alert('Bad file type!'); 
      return; 
     } 
     var reader = new FileReader(); 
     reader.onloadend = function (e) { 
      var imageLoader = new Image(); 
      imageLoader.onload = function() { 
       // process image 
      }; 
      imageLoader.src = e.target.result; 
     }; 
     reader.readAsDataURL(file); 
    }; 

inputFile2.onchange = ... (repeats all but process image) 
inputFile3.onchange = ... (repeats all but process image) 

只有在process image註釋代碼變化。我如何刪除周圍的重複代碼?

我知道JavaScript函數是對象。我如何定義一個函數對象併爲每個事件處理程序創建一個不同的實例,並將process image的不同函數傳遞給每個對象?

回答

3

您可以爲這些功能而封閉把個人回調作爲參數發電機:

function getChangeHandler(loadCallback) { 
    return function (e) { 
     var file = e.target.files[0]; 
     if (typeof file == 'undefined' || file == null) { 
      return; 
     } 
     var imageType = /image.*/; 
     if (!file.type.match(imageType)) { 
      window.alert('Bad file type!'); 
      return; 
     } 
     var reader = new FileReader(); 
     reader.onloadend = function (e) { 
      var imageLoader = new Image(); 
      imageLoader.onload = loadCallback; // <= uses the closure argument 
      imageLoader.src = e.target.result; 
     }; 
     reader.readAsDataURL(file); 
    }; 
} 
inputFile1.onchange = getChangeHandler(function() { /* custom process image */ }); 
inputFile2.onchange = getChangeHandler(function() { /* custom process image */ }); 
inputFile3.onchange = getChangeHandler(function() { /* custom process image */ }); 

的其它的,最終優越的方法是隻使用一個change -event處理程序所有的輸入,即由name或輸入的id動態地選擇所述自定義圖像處理器:

var imageProcessors = { 
    "box1": function() { … }, 
    "anotherbox": function() { … }, 
    … 
}; 
function changeHandler(e) { 
    var input = this; // === e.target 
    … 
    reader.onloadend = function (e) { 
     … 
     imageLoader.onload = imageProcessors[input.id]; 
    }; 
} 
// and bind this one function on all inputs (jQuery-style): 
$("#box1, #anotherbox, …").click(changeHandler); 
1

喲ü可以寫一個返回函數的函數:

function processFile(callback) { //callback is the unique file processing routine 
    return function(e) { 
     var file = e.target.files[0]; 
     if (typeof file == 'undefined' || file == null) { 
      return; 
     } 
     var imageType = /image.*/; 
     if (!file.type.match(imageType)) { 
      window.alert('Bad file type!'); 
      return; 
     } 
     var reader = new FileReader(); 
     reader.onloadend = function (e) { 
      var imageLoader = new Image(); 
      imageLoader.onload = callback; //Put it here! 
      imageLoader.src = e.target.result; 
     }; 
     reader.readAsDataURL(file); 
    }; 
} 

然後調用這樣的:

inputFile1.onchange = processFile(function() { 
     //file processing for number 1 
}); 
inputFile2.onchange = processFile(function() { 
     //file processing for number 2 
}); 
inputFile3.onchange = processFile(function() { 
     //file processing for number 3 
}); 
+0

無需使用返回函數的函數。只需將onchange分配給常用功能即可。 – jfriend00 2012-08-05 21:37:31

+1

@ jfriend00仍然需要一種將非公共函數與'input [type =「file」]關聯的方法。 – Dennis 2012-08-05 21:44:50

+0

咦?你可以從'e'參數中得到引發該事件的對象,並且我沒有看到你在額外的功能級別上做了額外的事情。它看起來並不需要我。 – jfriend00 2012-08-05 21:49:54

1

下面是一個EMCA5的解決方案,只是扔到組合。它根據元素綁定動態事件回調。

我假設每個字段都有一個ID(input1等),但對代碼進行了一些修改(即通過其他方式識別觸發器元素),這不是必需的。

Array.prototype.slice.call(document.querySelectorAll('input[type=file]')).forEach(function(element) { 

    /* prepare code specific to the element */ 
    var input_specific_code = (function() { 
     switch (element.id) { 
      case 'input1': return function() { /* #input1 code here */ }; 
      case 'input2': return function() { /* #input2 code here */ }; 
      case 'input3': return function() { /* #input3 code here */ }; 
     } 
    })(); 

    element.addEventListener('change', (function(input_specific_code) { return function(evt) { 
     var id_of_trigger_input = element.id; 

     /* common code here */ 

     /* element-specific code */ 
     input_specific_code(); 

     /* continuation of common code */ 

    }; })(input_specific_code), false); 
}); 
+0

爲什麼不直接在開關中放入'element.id'?此外,這種方法將創建n個函數,它們都包含所有n個輸入的代碼,但只需要其中的一個。 – Bergi 2012-08-05 21:42:26

+0

真的夠了 - 我只是在ECMA5中「素描」。修改爲使用閉包。 – Utkanos 2012-08-05 21:52:58