首页 新闻 会员 周边 捐助

HTML5简易取色器中遇到的jquery闭包问题

0
悬赏园豆:5 [已解决问题] 解决于 2013-05-13 20:25

现在在做一个有关图片处理的项目,用到了一些HTML5中的新特性,但是在颜色方面没有找到一个比较好用的取色器,所以就打算自己写一个。

实现过程比较简单,由于是第一次写类似插件的JS,涉及到了闭包问题,对于我来说还是第一次接触,所以难免遇到一些问题。

问题描述:

我 在$.fn.colorpicker = function (callbackFun, colorType)中接收两个参数(回调函数和返回值类型),问题是在我在两个地方调用$.fn.colorpicker并传递不同回调函数参数时,无 法更改包中的callbackFun值,导致每次返回的颜色都传递到第一次调用的回调函数中,希望有大牛帮我解释一下。

以下是js全部代码(暂时只支持火狐浏览器,其它未作兼容,实现比较匆忙,有什么需要改进的地方欢迎指点)

/*
colorpicker 1.0
Copyright (c) 2013 Jia Wencheng
Email:jiawencheng06@163.com

Name:colorpicker

 

Description:This a jQuery (Interface) colorpicker.
*/
(function ($) {
    $.fn.colorpicker = function (callbackFun, colorType) {

        originObj = $(this);
        colorType = colorType;
        callbackFun = callbackFun;

        $(document).ready(function () {
            if (!$("#divMain")[0]) {
                createElement();
                initColorMapBar();
                initColorMap([0, 0, 0]);
            }
        });

        if ($("#divMain").css("display") == "none") {
            $("#divMain").css("display", "block");
            initColorPicker();
        }
        else {
            $("#divMain").css("display", "none");
        }

        function initColorPicker() {
            var offsetTop;
            if ((originObj.offset().top + originObj.height() / 2) < 179) {
                offsetTop = 0;
            }
            else if ((originObj.offset().top + originObj.height() / 2 + 179) > window.innerHeight) {
                offsetTop = window.innerHeight - 356;
            }
            else {
                offsetTop = originObj.offset().top + originObj.height() / 2 - 179;
            }

            var offsetLeft;
            if ((window.innerWidth - originObj.offset().left - originObj.width()) < 325) {
                offsetLeft = originObj.offset().left - 325;
            }
            else {
                offsetLeft = originObj.offset().left + originObj.width() + 10;
            }

            $(divMain).css("top", offsetTop);
            $(divMain).css("left", offsetLeft);
        }

        function createElement() {
            divMain = document.createElement("div");
            divMain.id = "divMain";
            $(divMain).css("width", 315).css("height", 356).css("background-color", "#E8E8E8").css("position", "absolute").css("border", "1px solid #CCCCCC").css("-moz-user-select", "none").css("box-shadow", "10px 10px 10px rgba(0, 0, 0, 0.2)").css("display", "none").css("z-index", "10000");

            divHeader = document.createElement("div");
            divHeader.id = "divHeader";
            $(divHeader).css("height", 28).css("background", "-moz-linear-gradient(center top , #FFFFFF, #E5E5E5) repeat scroll 0 0 transparent").css("position", "relative").css("font-weight", 300).css("color", "#212121").css("cursor", "move").css("border-bottom", "1px solid #CCCCCC").css("box-shadow", "0 1px 0 0 #F4F4F4");
            divHeader.onmousedown = divHeaderMouseDown;
            divHeader.onmouseup = divHeaderMouseUp;
            divHeader.onmousemove = divHeaderMouseMove;
            divHeader.onmouseout = divHeaderMouseOut;

            spanName = document.createElement("span");
            spanName.id = "spanName";
            $(spanName).css("height", 28).css("padding-left", 20).css("line-height", "28px").css("text-shadow", "0 1px 0 #FFFFFF").css("background-color", "transparent").css("vertical-align", "top").css("word-wrap", "break-word").css("font-weight", 600).css("font-size", "12px").css("font-family", "HelveticaNeue-Light,Helvetica Neue Light,Helvetica Neue,Helvetica,Arial,Lucida Grande,sans-serif").css("float", "left").html("Color");
            spanName.click = cpClose;
            divHeader.appendChild(spanName);

            spanClose = document.createElement("span");
            spanClose.id = "spanClose";
            $(spanClose).css("background", "url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAArUlEQVQoz2OYOXMmAxSzAXEOEB8A4p9QfAAqxgZTB1MsDcTngfg/DnweqoYBZvIlPIphGKSGjQFqJUxwPxA7QE1cj8SGyeeANBxGMwmkyACIBYC4AE3uMAPUc8iC9////w8SV8DirJ/YNPSDNEA17UeT+wwSPIZsOtQpDUAcALXlPZL8MZCGfCSB9VDF/6EKG9A8nU9WsMIi7hIBxdLIMQ2zKR+aHODBCBWDJw0AyNRnE3i8MH4AAAAASUVORK5CYII=') no-repeat scroll 0 0 transparent").css("cursor", "pointer").css("height", "12px").css("width", "12px").css("opacity", "0.7").css("overflow", "hidden").css("position", "absolute").css("right", "15px").css("top", "7px").attr("title", "Close");
            spanClose.onclick = cpClose;
            divHeader.appendChild(spanClose);
            $(spanClose).mouseover(function () {
                $(this).css("opacity", "1");
            });
            $(spanClose).mouseout(function () {
                $(this).css("opacity", "0.7");
            });
            divMain.appendChild(divHeader);

            divCanvas = document.createElement("div");
            divCanvas.id = "divCanvas";
            $(divCanvas).css("height", 280).css("position", "relative").css("box-shadow", "0 1px 0 0 #F4F4F4").css("border-bottom", "1px solid #CCCCCC");

            divCPSubmit = document.createElement("div");
            divCPSubmit.id = "divCPSubmit";
            $(divCPSubmit).css("height", 40);

            canvasMap = document.createElement("canvas");
            canvasMap.id = "canvasMap";
            contextMap = canvasMap.getContext("2d");
            canvasMap.setAttribute("height", 260);
            canvasMap.setAttribute("width", 260)
            $(canvasMap).css("float", "left").css("position", "absolute").css("top", "10px").css("left", "10px");
            divCanvas.appendChild(canvasMap);

            canvasMapCover = document.createElement("canvas");
            canvasMapCover.id = "canvasMapCover";
            contextMapCover = canvasMapCover.getContext("2d");
            canvasMapCover.setAttribute("height", 260);
            canvasMapCover.setAttribute("width", 260)
            $(canvasMapCover).css("float", "left").css("position", "absolute").css("top", "10px").css("left", "10px").css("cursor", "crosshair").css("background-color", "transparent");
            canvasMapCover.onclick = colorMapClicked;
            divCanvas.appendChild(canvasMapCover);

            canvasMapBar = document.createElement("canvas");
            canvasMapBar.id = "canvasMapBar";
            contextMapBar = canvasMapBar.getContext("2d");
            canvasMapBar.setAttribute("height", 260);
            canvasMapBar.setAttribute("width", 30)
            $(canvasMapBar).css("float", "left").css("position", "absolute").css("top", "10px").css("right", "10px");
            divCanvas.appendChild(canvasMapBar);

            canvasMapBarCover = document.createElement("canvas");
            canvasMapBarCover.id = "canvasMapBarCover";
            contextMapBarCover = canvasMapBarCover.getContext("2d");
            canvasMapBarCover.setAttribute("height", 260);
            canvasMapBarCover.setAttribute("width", 30)
            $(canvasMapBarCover).css("float", "left").css("position", "absolute");
            $(canvasMapBarCover).css("position", "absolute").css("top", "10px").css("right", "10px").css("cursor", "crosshair");
            canvasMapBarCover.onclick = colorMapBarClicked;
            divCanvas.appendChild(canvasMapBarCover);

            divMain.appendChild(divCanvas);

            divFooter = document.createElement("div");
            divFooter.id = "divFooter";
            $(divFooter).css("height", "26px").css("float", "left").css("padding", "10px");

            divApply = document.createElement("div");
            divApply.id = "divApply";
            $(divApply).css("background", "none repeat scroll 0 0 transparent").css("border", "1px solid #CCCCCC").css("font-size", "100%").css("margin", "0px").css("outline", "0 none").css("padding", "0px").css("border-radius", "4px").css("vertical-align", "baseline").css("height", "26px").css("float", "left");

            divColor = document.createElement("div");
            divColor.id = "divColor";
            $(divColor).css("float", "left").css("background-color", "#DB0268").css("height", "13px").css("padding", "6px 5px 7px").css("width", "10px").css("border-radius", "4px 0 0 4px");
            divApply.appendChild(divColor);

            txtColorValue = document.createElement("input");
            txtColorValue.id = "txtColorValue";
            txtColorValue.type = "text";
            $(txtColorValue).css("float", "left").css("box-shadow", "0 -1px 0 0 rgba(255, 255, 255, 0.5) inset, 0 1px 0 rgba(255, 255, 255, 0.5)").css("color", "#444444").css("font-size", "11px").css("padding", "6px 5px 7px").css("width", "50px").css("text-transform", "uppercase").css("text-align", "center").css("border", "0px").css("-moz-user-select", "text");
            txtColorValue.onkeyup = txtColorValueKeyUp;
            divApply.appendChild(txtColorValue);

            btnApply = document.createElement("input");
            btnApply.id = "btnApply";
            btnApply.type = "button";
            $(btnApply).css("background-color", "#DB0268").css("box-shadow", "0 1px 0 rgba(255, 255, 255, 0.3) inset, 0 1px 0 rgba(255, 255, 255, 0.5))").css("border", "0px").css("border-radius", "0px 4px 4px 0px").css("color", "#FFFFFF").css("cursor", "pointer").css("float", "left").css("font-size", "11px").css("padding", "5px 10px 6px 10px").css("text-shadow", "0 -1px 0 rgba(0, 0, 0, 0.5)").attr("value", "Apply");
            btnApply.onclick = cpApply;
            divApply.appendChild(btnApply);

            divFooter.appendChild(divApply);

            btnCancel = document.createElement("input");
            btnCancel.id = "btnCancel";
            btnCancel.type = "button";
            $(btnCancel).css("background-color", "#E5E5E5").css("background-image", "-moz-linear-gradient(center top , #F4F4F4, #E5E5E5)").css("background-repeat", "repeat-x").css("box-shadow", "0 1px 0 rgba(255, 255, 255, 0.3) inset, 0 1px 0 rgba(255, 255, 255, 0.5)").css("border", "1px solid #D1D1D1").css("border-radius", "4px 4px 4px 4px").css("color", "#212121").css("text-shadow", "0 1px 1px rgba(255, 255, 255, 0.75)").css("cursor", "pointer").css("float", "right").css("position", "relative").css("left", "90px").css("margin-bottom", "0px").css("font-size", "11px").css("-moz-user-select", "-moz-none").css("padding", "5px 10px 6px 10px").attr("value", "Cancel");
            btnCancel.onclick = cpClose;
            divApply.appendChild(btnCancel);

            divFooter.appendChild(btnCancel);

            divMain.appendChild(divFooter);

            jQuery("body").prepend(divMain);
            $("#divCPMain").css("display", "block");
        };

        function initColorMapBar() {
            var color = 0;

            var fillColor = contextMapBar.createLinearGradient(1, 1, 30, 1);

            for (var i = 0; i < 6; i++) {
                color = i % 2 == 0 ? 0 : 255;

                for (var j = 1; j < 45; j++) {
                    if (i % 2 == 0) {
                        if (color > 248 && color <= 255) {
                            color = 255;
                        }
                        else {
                            color = color + 6;
                        }
                    }
                    else {
                        if (color < 7 && color >= 0) {
                            color = 0;
                        }
                        else {
                            color = color - 6;
                        }
                    }

                    switch (i) {
                        case 0:
                            fillColor.addColorStop(0, "rgba(255,0," + color + ",1)");
                            break;
                        case 1:
                            fillColor.addColorStop(0, "rgba(" + color + ",0,255,1)");
                            break;
                        case 2:
                            fillColor.addColorStop(0, "rgba(0," + color + ",255,1)");
                            break;
                        case 3:
                            fillColor.addColorStop(0, "rgba(0,255," + color + ",1)");
                            break;
                        case 4:
                            fillColor.addColorStop(0, "rgba(" + color + ",255,0,1)");
                            break;
                        case 5:
                            fillColor.addColorStop(0, "rgba(255," + color + ",0,1)");
                            break;
                    }

                    fillColor.addColorStop(1, "rgba(0,0,0,1)");

                    contextMapBar.beginPath();
                    contextMapBar.moveTo(1, j + 43 * i);
                    contextMapBar.lineTo(30, j + 43 * i);
                    contextMapBar.lineWidth = 2;
                    contextMapBar.strokeStyle = fillColor;
                    contextMapBar.stroke();
                }
            }
        }

        function initColorMap(imageData) {

            var fillColor = contextMapBar.createLinearGradient(1, 1, 1, 260);

            fillColor.addColorStop(1, "rgba(0,0,0,1)");

            for (var i = 0; i < 260; i++) {
                fillColor.addColorStop(0, "rgba(" + (255 - Math.round((255 - imageData[0]) * i / 260)) + "," + (255 - Math.round((255 - imageData[1]) * i / 260)) + "," + (255 - Math.round((255 - imageData[2]) * i / 260)) + ",1)");

                contextMap.beginPath();
                contextMap.moveTo(i + 1, 1);
                contextMap.lineTo(i + 1, 260);
                contextMap.lineWidth = 2;
                contextMap.strokeStyle = fillColor;
                contextMap.stroke();
            }
        }

        function drawMapCrossMark(coorX, coorY, contextObj) {
            contextObj.clearRect(0, 0, 260, 260);
            contextObj.beginPath();
            contextObj.moveTo(coorX - 4, coorY);
            contextObj.lineTo(coorX - 1, coorY);
            contextObj.moveTo(coorX, coorY - 4);
            contextObj.lineTo(coorX, coorY - 1);
            contextObj.moveTo(coorX + 1, coorY);
            contextObj.lineTo(coorX + 4, coorY);
            contextObj.moveTo(coorX, coorY + 1);
            contextObj.lineTo(coorX, coorY + 4);
            contextObj.lineWidth = 1;
            contextObj.strokeStyle = "#FFF";
            contextObj.stroke();
        }

        function colorMapClicked(e) {
            drawMapCrossMark(e.layerX, e.layerY, contextMapCover);
            var colorData = contextMap.getImageData(e.layerX, e.layerY, 1, 1).data;
            $(txtColorValue).val((colorData[0].toString(16).length == 2 ? colorData[0].toString(16) : "0" + colorData[0].toString(16)) + (colorData[1].toString(16).length == 2 ? colorData[1].toString(16) : "0" + colorData[1].toString(16)) + (colorData[2].toString(16).length == 2 ? colorData[2].toString(16) : "0" + colorData[2].toString(16)));
            $(divColor).css("background-color", "#" + $(txtColorValue).val());
        }

        function colorMapBarClicked(e) {
            drawMapCrossMark(e.layerX, e.layerY, contextMapBarCover);
            var colorData = contextMapBar.getImageData(e.layerX, e.layerY, 1, 1).data;
            initColorMap(colorData);
            $(txtColorValue).val((colorData[0].toString(16).length == 2 ? colorData[0].toString(16) : "0" + colorData[0].toString(16)) + (colorData[1].toString(16).length == 2 ? colorData[1].toString(16) : "0" + colorData[1].toString(16)) + (colorData[2].toString(16).length == 2 ? colorData[2].toString(16) : "0" + colorData[2].toString(16)));
            $(divColor).css("background-color", "#" + $(txtColorValue).val());
        }

        function txtColorValueKeyUp(e) {
            var colorData = $(this).val().split('');

            if (colorData.length >= 3 && colorData.length < 6) {
                colorData = [colorData[0], colorData[0], colorData[1], colorData[1], colorData[2], colorData[2]];
            }

            var isColorDataIsValid = true;
            for (var i = 0; i < 6; i++) {
                if (!(colorData[i].charCodeAt() >= 48 && colorData[i].charCodeAt() <= 57) || (colorData[i].charCodeAt() >= 65 && colorData[i].charCodeAt() <= 70) || (colorData[i].charCodeAt() >= 97 && colorData[i].charCodeAt() <= 102)) {
                    isColorDataIsValid = false;
                    break;
                }
            }
            if (isColorDataIsValid) {
                $(divColor).css("background-color", "#" + $(txtColorValue).val());
            }
        }

        function divHeaderMouseDown(e) {
            isMouseDown = true;
            layerXTemp = e.layerX;
            layerYTemp = e.layerY;
            $("#divMain").css("opacity", "0.9");
        }

        function divHeaderMouseUp(e) {
            isMouseDown = false;
            $("#divMain").css("opacity", "1");
        }

        function divHeaderMouseMove(e) {
            if (isMouseDown) {
                $("#divMain").css("left", e.clientX - layerXTemp);
                $("#divMain").css("top", e.clientY - layerYTemp);
            }
        }

        function divHeaderMouseOut(e) {
            isMouseDown = false;
            $("#divMain").css("opacity", "1");
        }

        function cpApply() {
            if (typeof callbackFun == "function") {
                if (colorType == "rgb") {
                    callbackFun(new colorRgb($("#divColor").css("background-color").split(')')[0].substring(4).split(',')));
                }
                else {
                    callbackFun(colorHex($("#divColor").css("background-color").split(')')[0].substring(4).split(',')).toLocaleUpperCase());
                }
            }
            $("#divMain").css("display", "none");
        }

        function cpClose() {
            $("#divMain").css("display", "none");
        }

        function colorRgb(rgb) {
            this.r = rgb[0],
            this.g = rgb[1],
            this.b = rgb[2]
        }

        function colorHex(rgb) {
            return "#" + colorSingelHex(parseInt(rgb[0])) + colorSingelHex(parseInt(rgb[1])) + colorSingelHex(parseInt(rgb[2]));
        }

        function colorSingelHex(value) {
            return value.toString(16).length > 1 ? value.toString(16) : "0" + value.toString(16);
        }
    }

})(jQuery);

Brian_C#的主页 Brian_C# | 菜鸟二级 | 园豆:211
提问于:2013-05-13 20:13
< >
分享
最佳答案
0

原因:由于闭包后参数和变量不会被垃圾回收机制回收,会长期贮存在内存中。

解决方案:将代码改为在闭包体外申请变量,在包内赋值——问题解决。

Brian_C# | 菜鸟二级 |园豆:211 | 2013-05-13 20:24
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册