2012-08-05 35 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