Javascript - 需要设计模式建议

时间:2010-10-25 14:58:56

标签: javascript design-patterns

喂,

我在Javascript中有3个不同的功能,第一个替换用UL创建的HTML Selectboxs宽度自定义选择框。

,另外2个分别替换Checkbox和Radio按钮。

现在我想从这些函数中派生出类,并且需要你的建议,将这些函数组织到课堂中的最佳方法是什么,是否可以实现?

我非常感谢你的帮助。

感谢。

以下是一些示例代码。

function replaceSelect(formid) {

    var form = $(formid);
    if (!form) return;

    invisibleSelectboes = document.getElementsByClassName("optionsDivInvisible");
    if (invisibleSelectboes.length > 0) {
        for (var i = 0; i < invisibleSelectboes.length; i++) {
            document.body.removeChild(invisibleSelectboes[i]);
        }
    }

    var selects = [];
    var selectboxes = form.getElementsByTagName('select');

    var selectText = "Bitte auswählen";
    var selectRightSideWidth = 21;
    var selectLeftSideWidth = 8;
    selectAreaHeight = 21;
    selectAreaOptionsOverlap = 2;

    // Access all Selectboxes in Search mask.
    for (var cfs = 0; cfs < selectboxes.length; cfs++) {
        selects.push(selectboxes[cfs]);
    }

    // Replace the select boxes
    for (var q = 0; q < selects.length; q++) {
        if (selects[q].className == "") continue;

        var onchangeEvent = selects[q].onchange;

        //create and build div structure
        var selectArea = document.createElement('div');
        var left = document.createElement('div');
        var right = document.createElement('div');
        var center = document.createElement('div');
        var button = document.createElement('a');
        //        var text = document.createTextNode(selectText);
        var text = document.createTextNode('');
        center.id = "mySelectText" + q;

        if ( !! selects[q].getAttribute("selectWidth")) {
            var selectWidth = parseInt(selects[q].getAttribute("selectWidth"));
        } else {
            var selectWidth = parseInt(selects[q].className.replace(/width_/g, ""));
        }

        center.style.width = selectWidth + 'px';
        selectArea.style.width = selectWidth + selectRightSideWidth + selectLeftSideWidth + 'px';

        if (selects[q].style.display == 'none' || selects[q].style.visibility == 'hidden') {
            selectArea.style.display = 'none';
        }

        button.style.width = selectWidth + selectRightSideWidth + selectLeftSideWidth + 'px';
        button.style.marginLeft = -selectWidth - selectLeftSideWidth + 'px';
        //  button.href = "javascript:toggleOptions( + q + ")";
        Event.observe(button, 'click', function (q) {
            return function (event) {
                clickObserver(event, q)
            }
        }(q));

        button.onkeydown = this.selectListener;
        button.className = "selectButton"; //class used to check for mouseover
        selectArea.className = "selectArea";

        selectArea.id = "sarea" + q;
        left.className = "left";
        right.className = "right";
        center.className = "center";
        right.appendChild(button);
        center.appendChild(text);
        selectArea.appendChild(left);
        selectArea.appendChild(right);
        selectArea.appendChild(center);
        //hide the select field
        selects[q].style.display = 'none';
        //insert select div
        selects[q].parentNode.insertBefore(selectArea, selects[q]);

        //build & place options div
        var optionsDiv = document.createElement('div');

        if (selects[q].getAttribute('width')) optionsDiv.style.width = selects[q].getAttribute('width') + 'px';
        else optionsDiv.style.width = selectWidth + 8 + 'px';

        optionsDiv.className = "optionsDivInvisible";
        optionsDiv.id = "optionsDiv" + q;
        optionsDiv.style.left = findPosX(selectArea) + 'px';
        optionsDiv.style.top = findPosY(selectArea) + selectAreaHeight - selectAreaOptionsOverlap + 'px';

        //get select's options and add to options div
        for (var w = 0; w < selects[q].options.length; w++) {
            var optionHolder = document.createElement('p');

            if (selects[q].options[w].className == "informal") {
                var optionLink = document.createElement('a');
                var optionTxt = document.createTextNode(selects[q].options[w].getAttribute('text'));
                optionLink.innerHTML = selects[q].options[w].getAttribute('text');
                optionLink.className = "informal";
                cic.addEvent(optionLink, 'click', function (event) {
                    Event.stop(event);
                });

                Event.observe(optionLink, 'mouseover', function (event) {
                    Event.stop(event);
                });

                Event.observe(optionLink, 'mouseout', function (event) {
                    Event.stop(event);
                });
            }
            else {
                var optionLink = document.createElement('a');
                var optionTxt = document.createTextNode(selects[q].options[w].text);
                optionLink.appendChild(optionTxt);
                cic.addEvent(optionLink, 'click', function (id, w, q, onchangeEvent) {
                    return function () {
                        showOptions(q);
                        selectMe(selects[q].id, w, q, onchangeEvent);
                    }
                }(selects[q].id, w, q, onchangeEvent));
            }

            //optionLink.href = "javascript:showOptions(" + q + "); selectMe('" + selects[q].id + "'," + w + "," + q + ");";

            optionHolder.appendChild(optionLink);
            optionsDiv.appendChild(optionHolder);

            if (selects[q].options[w].selected) {
                selectMe(selects[q].id, w, q);
            }
        }
        document.getElementsByTagName("body")[0].appendChild(optionsDiv);
        Event.observe(optionsDiv, 'mouseleave', function (submenuid) {
            optionsDiv.className = 'optionsDivInvisible'
        });

        cic.addEvent(optionsDiv, 'click', function (event) {
            if (event.stopPropagation) event.stopPropagation();
            else event.cancelBubble = true;
        });

    }
    form.setStyle({
        visibility: 'visible'
    });
}​

4 个答案:

答案 0 :(得分:3)

从它的声音来看,您希望创建一个统一的API来封装所有这些“表单增强”功能。可能是这样的:

var formEnhancement = {
    SelectBox: function(){ /* ... */ },
    CheckBox: function(){ /* ... */ },
    RadioButton: function(){ /* ... */ }
};

formEnhancement.SelectBox.prototype = { /* ... define methods ... */ };
// etc. (other prototypes)

// Call something:
var myEnhancedSelectBox = new formEnhancement.SelectBox(
    document.getElementById('id-of-a-select-box')
);

这是否可以回答您的问题?

答案 1 :(得分:3)

我会去

var Library = (function()
{
    function _selectBox()
    {
        // stuff
    }

    function _checkBox()
    {
        // stuff
    }

    function _radioButton()
    {
        // stuff
    }

    return {
        SelectBox : _selectBox,
        CheckBox : _checkBox,
        RadioButton : _radioButton
    };
})();

var Library = (function()
{
    return {
        SelectBox : function()
        {
            // stuff
        },

        CheckBox : function()
        {
            // stuff
        },

        RadioButton : function()
        {
            // stuff
        }
    };
})();

[编辑]
通过这种方式,您实际上可以声明只能从库本身访问的“私有”变量,只需在var foo="bar";的声明中声明Library,创建一个无法从外部访问的foo变量,但是可以通过库中的任何东西访问,这就是为什么像我的例子中的_selectBox这样的函数保持私有,但仍然可以通过Library.SelectBox访问,这将是“公共getter”
[/编辑]

也是,而不是

var Library = (function(){})();
你可以这样做:

var Library = Library || {};

Library.UI = (function(){})();

这样,您可以保留代码库的单独部分,可以将它们保存在单独的文件中,这些文件不关心它们的加载顺序,只要它们有

var Library = Library || {};

在他们之上

然后会像这样调用函数:

Library.SelectBox();

或者您选择使用“子类”

Library.UI.SelectBox();

答案 2 :(得分:1)

将函数放在命名空间中:

声明如下:

FormUtils = {};

并添加其属性,这将是您的功能

FormUtils.replaceSelect = function () {/*your code*/};
FormUtils.replaceCheckbox = function () {/*your code*/};
FormUtils.replaceRadio = function () {/*your code*/};

然后用它们的命名空间调用这个函数:

FormUtils.replaceSelect();

这是一个简单且非常公认的javascript设计模式

答案 3 :(得分:1)

所有答案都是一般模式,我认为它们都没有真正有用。仅仅因为你将3个巨大的函数放入对象中并不会使代码模块化,可重用,可维护。

所以我的第一个建议是使用 function decomposition 。你提到了继承。现在,如果您的代码基本上由这3个巨型函数组成,则无法继承或共享任何内容。您应该将功能逻辑按目的分成更小,更直接的功能逻辑。

一个很好的例子就是你提到替换一词在所有情况下都是相关的。也许你可以设置一个独立于元素类型负责DOM替换的函数。这些功能可以在您的模块之间共享,使您的代码更加健壮,并允许您 DRY

组织此过程的最佳方式称为一厢情愿,当您使用直观且有用的功能解决您的问题时,即使它们甚至可能不存在。这与您如何设计有效的相互作用有关。