如何删除DOM事件处理程序的重复JavaScript代码

How to remove duplicate JavaScript code of DOM event handler?

本文关键字:程序 代码 JavaScript 事件处理 DOM 何删除 删除      更新时间:2023-09-26

我正在尝试删除重复的JavaScript代码。我有一页有很多<input type="file">。每个加载一个图像并执行一些不同的处理。问题是我有许多重复的以下代码:

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的不同函数传递给每个对象?

您可以为这样的函数制作一个生成器,该生成器带有一个以单个回调为参数的闭包:

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-事件处理程序,通过输入的nameid动态选择自定义图像处理器:

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

您可以编写一个返回函数的函数:

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

这里有一个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);
});