Javascript - 设计模式建议需要

3

您好,

我有三个不同的JavaScript函数,第一个用UL创建自定义selectbox替换HTML Selectbox的宽度。

另外两个分别替换复选框和单选按钮。

现在我想从这些函数中派生类,并需要您的建议,最好的组织这些函数成类的方式是什么,是否可以继承?

我非常感谢您的帮助。

谢谢。

以下是一些示例代码。

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

2
你有一些我们可以查看的代码吗? - scunliffe
4个回答

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

这个回答解决了您的问题吗?

我该如何在formEnhancement类中保存常见属性? - user160820
你可以将通用属性保存在formEnhancement原型中。formEnhancement.prototype = {} ...这样,每个formEnhancement实例都共享这些常见方法,并且任何继承formEnhancement的对象也可以访问这些方法。 - Mike Rifgin

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

[编辑]
通过在Library的声明中仅声明 var foo ="bar";,可以实际上声明只能从库本身访问的“私有”变量。这样做使得foo变量不能从外部访问,但可以被Library内的任何内容访问,这就是为什么像我的示例中的_selectBox函数仍然保持私有,但仍可以通过Library.SelectBox访问,这将是“公共getter”
[/编辑]

此外,与其使用

var Library = (function(){})();

您可以像这样做:
var Library = Library || {};

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

这样,您可以将代码库的不同部分分开,将它们放在不同的文件中,这些文件不关心它们被加载的顺序,只要它们存在即可。
var Library = Library || {};

在它们的顶部, 然后这些函数将被这样调用:
Library.SelectBox();

或者在你选择使用“子类”的情况下。
Library.UI.SelectBox();

1
将函数放入命名空间中:
像这样进行声明:
FormUtils = {};

并添加它的属性,这些属性将成为您的函数

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

然后您可以使用它们的命名空间调用这些函数:

FormUtils.replaceSelect();

这是一种简单且在JavaScript中非常受欢迎的设计模式。


1

所有的答案都是一般性的模式,我认为它们都不是真正有用的。仅仅因为你把你的三个巨大的函数放到一个对象中并不能使你的代码具有模块化、可重用性和可维护性。

所以我的第一个建议是利用函数分解。你已经提到了继承。现在如果你的代码基本上由这三个巨大的函数组成,那么就没有什么可以被继承或共享的了。你应该按照目的将函数逻辑分离成更小、更直观的函数。

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

组织这个过程的最佳方式是称之为愿望式思考,当你使用直观和有用的函数来解决问题时,即使它们可能不存在。这与你如何设计有效的接口有关。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接