JavaScript双重函数调用覆盖第一个函数调用

时间:2014-07-26 13:09:06

标签: javascript addeventlistener

在开始详细介绍之前,请先查看出现此问题的实例 - http://jsfiddle.net/66HFU/(本文底部的脚本代码)

现在,如果你点击最后一行的任何图像,它会显示这些。但是,如果您单击上排图像,则会显示下面的行图像。

进一步调查显示,由于某种原因,调用函数选择器元素的字母仅与事件侦听器绑定,而第一个调用的函数选择器元素则不会。

所以,我想知道是否有任何方法可以使函数调用独立,因此后一个函数调用不会覆盖第一个函数(如果这样可以解决问题,当然)?

事件函数在元素上绑定的位置可以在函数 f_AddEvents 的第一行找到。

用于初始化Light Box的主函数调用位于代码的底部,如下所示:

LightBox.init({
    selector: "[data-simplbox='demo1']",
    boxId: "simplbox"
});

LightBox.init({
    selector: "[data-simplbox='demo2']",
    boxId: "simplbox",
    imageLoadStart: activityIndicatorOn,
    imageLoadEnd: activityIndicatorOff
});

所有代码:

;(function (window, document, undefined) {
var docElem = document.documentElement;

var DomM = (function() {
    var f_ToDOMStyle = function (p_Style) {
        return p_Style.replace(/\-[a-z]/g, function (p_Style) {
            return p_Style.charAt(1).toUpperCase();
        });
    };

    return {
        event: {
            set: function (p_Element, p_Events, p_Function) {
                var i = 0,
                    j = 0;

                p_Events = p_Events.split(" ");

                if (!p_Element.length) {
                    for (i = 0; i < p_Events.length; i++) {
                        p_Element.addEventListener(p_Events[i], p_Function, false);
                    }
                } else {
                    for (i = 0; i < p_Element.length; i++) {
                        for (j = 0; j < p_Events.length; j++) {
                            p_Element[i].addEventListener(p_Events[j], p_Function, false);
                        }
                    }
                }
            }
        },
        css: {
            set: function (p_Element, p_Style) {
                var j;
                if (!p_Element.length) {
                    for (j in p_Style) {
                        if (p_Style.hasOwnProperty(j)) {
                            j = f_ToDOMStyle(j);
                            p_Element.style[j] = p_Style[j];
                        }
                    }
                } else {
                    for (var i = 0; i < p_Element.length; i++) {
                        for (j in p_Style) {
                            if (p_Style.hasOwnProperty(j)) {
                                j = f_ToDOMStyle(j);
                                p_Element[i].style[j] = p_Style[j];
                            }
                        }
                    }
                }
            }
        }
    };
}());

var _LightBox = {
    f_MergeObjects: function (p_Original, p_Updates) {
        for (var i in p_Updates) {
            if (p_Updates.hasOwnProperty(i)) {
                p_Original[i] = p_Updates[i];
            }
        }
        return p_Original;
    },

    f_isFunction: function (p_Function) {
        return !!(p_Function && p_Function.constructor && p_Function.call && p_Function.apply);
    },

    f_Initialize: function (p_Options) {
        var base = this;

        base.m_Options = base.f_MergeObjects(_LightBox.options, p_Options || {});
        base.m_Elements = document.querySelectorAll(base.m_Options.selector);
        base.m_ElementsLength = base.m_Elements.length - 1;
        base.m_Body = document.getElementsByTagName("body")[0];

        base.m_CurrentImageElement = false;
        base.m_CurrentImageNumber = 0;
        base.m_Direction = 1;
        base.m_InProgress = false;
        base.m_InstalledImageBox = false;

        console.log(base.m_Elements);

        // Check if hardware acceleration is supported and check if touch is enabled.
        base.f_CheckBrowser();

        // Adds events.
        base.f_AddEvents();
    },

    f_CheckBrowser: function () {
        var base = this,
            isTouch = "ontouchstart" in window || window.navigator.msMaxTouchPoints || navigator.maxTouchPoints || false,
            vendors = ["ms", "O", "Moz", "Webkit", "Khtml"],
            rootStyle = docElem.style,
            hardwareAccelerated = false;

        if ("transform" in rootStyle) {
            hardwareAccelerated = true;
        } else {
            while (vendors.length) {
                if (vendors.pop() + "Transform" in rootStyle) {
                    hardwareAccelerated = true;
                }
            }
        }

        base.browser = {
            "isHardwareAccelerated": hardwareAccelerated,
            "isTouch": isTouch
        };
    },

    f_AddEvents: function () {
        var base = this;

        // Add open image event on images.
        for (var i = 0; i < base.m_Elements.length; i++) {
            (function (i) {
                base.m_Elements[i].addEventListener("click", function (event) {
                    event.preventDefault();

                    console.log(base.m_Elements[i]);

                    if (base.f_isFunction(base.m_Options.onImageStart)) {
                        base.m_Options.onImageStart();
                    }

                    base.f_OpenImage(i);
                }, false);
            })(i);
        }

        // Resize event for window.
        window.addEventListener("resize", function (event) {
            event.preventDefault();

            base.f_SetImage();
        }, false);

        // Add keyboard support.
        if (base.m_Options.enableKeyboard) {
            var keyBoard = {
                left: 37,
                right: 39,
                esc: 27
            };

            window.addEventListener("keydown", function (event) {
                event.preventDefault();

                if (base.m_CurrentImageElement) {
                    if (base.m_InProgress) {
                        return false;
                    }

                    switch (event.keyCode) {
                        case keyBoard.left:
                            // If the previous one is out of target range then go to the last image.
                            if ((base.m_CurrentImageNumber - 1) < 0) {
                                base.f_OpenImage(base.m_ElementsLength, "left");
                            } else {
                                base.f_OpenImage(base.m_CurrentImageNumber - 1, "left");
                            }

                            return false;

                        case keyBoard.right:
                            // If the next one is out of target range then go to the first image.
                            if ((base.m_CurrentImageNumber + 1) > base.m_ElementsLength) {
                                base.f_OpenImage(0, "right"); 
                            } else {
                                base.f_OpenImage(base.m_CurrentImageNumber + 1, "right");
                            }

                            return false;

                        case keyBoard.esc:
                            base.f_QuitImage();
                            return false;
                    }
                }

                return false;
            }, false);
        }

        // Add document click event.
        if (base.m_Options.quitOnDocumentClick) {
            document.body.addEventListener("click", function (event) {
                var target = event.target ? event.target : event.srcElement;

                event.preventDefault();

                if (target && target.id != "imagelightbox" && base.m_CurrentImageElement && !base.m_InProgress && base.m_InstalledImageBox) {
                    base.f_QuitImage();
                    return false;
                }

                return false;
            }, false);
        }
    },

    f_OpenImage: function (p_WhichOne, p_Direction) {
        var base = this,
            newFragment = document.createDocumentFragment(),
            newImageElement = document.createElement("img"),
            target = base.m_Elements[p_WhichOne].getAttribute("href");

        if (base.m_CurrentImageElement) {
            base.f_RemoveImage();
        }

        if (base.f_isFunction(base.m_Options.imageLoadStart)) {
            base.m_Options.imageLoadStart();
        }

        base.m_InProgress = true;
        base.m_InstalledImageBox = false;
        base.m_Direction = typeof p_Direction === "undefined" ? 1 : p_Direction == "left" ? -1 : 1;

        newImageElement.setAttribute("src", target);
        newImageElement.setAttribute("alt", "LightBox");
        newImageElement.setAttribute("id", base.m_Options.boxId);

        newFragment.appendChild(newImageElement);
        base.m_Body.appendChild(newFragment);

        base.m_CurrentImageElement = document.getElementById(base.m_Options.boxId);
        base.m_CurrentImageElement.style.opacity = "0";
        base.m_CurrentImageNumber = p_WhichOne;

        if (base.m_Options.quitOnImageClick) {
            base.f_ImageClickEvent = function (event) {
                event.preventDefault();
                base.f_QuitImage();
            };

            base.m_CurrentImageElement.addEventListener("click", base.f_ImageClickEvent, false);
        }

        if (base.browser.isHardwareAccelerated) {
            DomM.css.set(base.m_CurrentImageElement, base.f_AddTransitionSpeed(base.m_Options.animationSpeed));
        }

        base.f_SetImage();

        DomM.css.set(base.m_CurrentImageElement, base.f_doTranslateX(50 * base.m_Direction + "px"));

        setTimeout(function () {
            if (base.browser.isHardwareAccelerated) {
                setTimeout(function () {
                    DomM.css.set(base.m_CurrentImageElement, base.f_doTranslateX("0px"));
                }, 50);
            }

            if (base.f_isFunction(base.m_Options.imageLoadEnd)) {
                base.m_Options.imageLoadEnd();
            }
        }, 20);

        setTimeout(function () {
            base.m_InProgress = false;
            base.m_InstalledImageBox = true;
        }, base.m_Options.animationSpeed - 200);
    },

    f_SetImage: function () {
        var base = this,
            screenHeight = window.innerHeight || docElem.offsetHeight,
            screenWidth = window.innerWidth || docElem.offsetWidth,
            tmpImage = new Image(),
            imageWidth, imageHeight, imageSizeRatio;

        if (!base.m_CurrentImageElement) {
            return;
        }

        tmpImage.onload = function () {
            imageWidth = this.width;
            imageHeight = this.height;
            imageSizeRatio = imageWidth / imageHeight;

            if (Math.floor(screenWidth/imageSizeRatio) > screenHeight) {
                imageWidth = screenHeight * imageSizeRatio * 0.7;
                imageHeight = screenHeight * 0.7;
            } else {
                imageWidth = screenWidth * 0.7;
                imageHeight = screenWidth / imageSizeRatio * 0.7;
            }

            DomM.css.set(base.m_CurrentImageElement, {
                "top": ((screenHeight - imageHeight) / 2) + "px",
                "left": ((screenWidth - imageWidth) / 2) + "px",
                "width": Math.floor(imageWidth) + "px",
                "height": Math.floor(imageHeight) + "px",
                "opacity": 1
            });
        };

        tmpImage.src = base.m_CurrentImageElement.getAttribute("src");
    },

    f_RemoveImage: function () {
        var base = this;

        if (base.m_CurrentImageElement) {
            if (base.f_isFunction(base.m_Options.quitOnImageClick)) {
                base.m_CurrentImageElement.removeEventListener("click", base.f_ImageClickEvent, false);
            }

            base.m_CurrentImageElement.parentNode.removeChild(base.m_CurrentImageElement);
            base.m_CurrentImageElement = false;
        }
        return false;
    },

    f_QuitImage: function () {
        var base = this;

        if (base.m_CurrentImageElement) {
            setTimeout(function () {
                DomM.css.set(base.m_CurrentImageElement, {
                    "opacity": 0,
                    "transition": ("opacity " + base.m_Options.fadeOutSpeed + "ms ease")
                });

                setTimeout(function () {
                    base.f_RemoveImage();

                    if (base.f_isFunction(base.m_Options.onImageQuit)) {
                        base.m_Options.onImageQuit();
                    }

                }, base.m_Options.fadeOutSpeed);
            }, 20);
        }
    },

    f_IsValidSource: function (p_Src) {
        return new RegExp().test(p_Src);
    },

    f_doTranslateX: function (p_Pixels) {
        return {
            "-webkit-transform": "translateX(" + p_Pixels + ")",
            "-moz-transform": "translateX(" + p_Pixels + ")",
            "-o-transform": "translateX(" + p_Pixels + ")",
            "-ms-transform": "translateX(" + p_Pixels + ")",
            "transform": "translateX(" + p_Pixels + ")"
        };
    },

    f_AddTransitionSpeed: function (p_Speed) {
        var base = this;

        return {
            "-webkit-transition": "transform " + p_Speed + "ms ease, opacity " + base.m_Options.fadeInSpeed + "ms ease",
            "-moz-transition": "transform " + p_Speed + "ms ease, opacity " + base.m_Options.fadeInSpeed + "ms ease",
            "-o-transition": "transform " + p_Speed + "ms ease, opacity " + base.m_Options.fadeInSpeed + "ms ease",
            "transition": "transform " + p_Speed + "ms ease, opacity " + base.m_Options.fadeInSpeed + "ms ease"
        };
    }
};

_LightBox.options = {
    selector: "[data-imagelightbox]",
    boxId: "imagelightbox",
    allowedTypes: "png|jpg|jpeg|gif",

    quitOnImageClick: true,
    quitOnDocumentClick: true,
    enableKeyboard: true,

    animationSpeed: 750,
    fadeInSpeed: 500,
    fadeOutSpeed: 200,

    imageLoadStart: function () {},
    imageLoadEnd: function () {},
    onImageQuit: function () {},
    onImageStart: function () {}
};

LightBox.init = function (p_Options) {
    _LightBox.f_Initialize(p_Options);
};
})(window, document, window.LightBox = window.LightBox || {});

var activityIndicatorOn = function () {
    var newE = document.createElement("div"),
        newB = document.createElement("div");

    newE.setAttribute("id", "imagelightbox-loading");
    newE.appendChild(newB);
    document.body.appendChild(newE);
},
activityIndicatorOff = function () {
    var elE = document.getElementById("imagelightbox-loading");
    elE.parentNode.removeChild(elE);
};

LightBox.init({
    selector: "[data-simplbox='demo1']",
    boxId: "simplbox"
});

LightBox.init({
    selector: "[data-simplbox='demo2']",
    boxId: "simplbox",
    imageLoadStart: activityIndicatorOn,
    imageLoadEnd: activityIndicatorOff
});

1 个答案:

答案 0 :(得分:0)

您的代码几乎正常运行。你处理得很糟糕的事实是你可以执行几个init。在每个init上,您将覆盖一些项目,尤其是使用以下行:

base.m_Elements = document.querySelectorAll(base.m_Options.selector);

所以base.m_Elements只会包含最后一个init的元素 (基于名称'init',我想知道真正的用例是不允许只调用一次init ...)

快速修复是使用以下命令执行单个init:

LightBox.init({
    selector: "[data-simplbox='demo1'],[data-simplbox='demo2']",
    boxId: "simplbox"
});

(删除对init的两次调用) 这里有效。

http://jsfiddle.net/gamealchemist/66HFU/1/

所以我想你要么支持几个init,要么(实际上更容易维护),在多个init上抛出异常,并期望lib用户在单个init调用中编写正确的选择器。

编辑:为您的问题提供超快速解决方案:不要将LightBox作为单身人士,而是将其作为一个类:

 function LightBox( initArguments ) {
   // something like what was done in init

 }

 LightBox.prototype = {
   f_RemoveImage : function() {
   } ,
   f_OpenImage : function( ..., ... ) {
   } ,
    ...
 } 

然后你可以毫无问题地致电:

var demo1LB = new LightBox({ selector: "[data-simplbox='demo1']", 
                              boxId: "simplbox" });

var demo2LB = new LightBox({ selector: "[data-simplbox='demo2']", 
                              boxId: "simplbox" });