2010-10-25 86 views
3

Hallo,Javascript - 需要Designpattern建议

我有3个不同的Javascript函数,第一个函数取代了使用UL创建的HTML Selectboxs宽度自定义选择框。

另外2个替换复选框和单选按钮。

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

我真的很理解你的帮助。

谢谢。

这是一些示例代码。

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 2010-10-25 15:02:02

回答

1

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

所以我的第一个建议是利用function decomposition。你已经提到了继承。现在如果你的代码基本上由这3个巨大的函数组成,那么任何东西都不能被继承或共享。您应该将功能逻辑分成更小,更直接的功能逻辑。

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

组织这个过程的最好方法叫做如意算盘,当你用直观和有用的功能解决你的问题时,即使它们甚至不存在。这与您如何设计有效的交互有关。

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

这是否回答了您的问题?

+0

如何在FormEnhancement类中保存公共属性? – user160820 2010-10-25 15:23:03

+0

您可以将常见属性保存在FormEnhancement原型中。 formEnhancement.prototype = {} ...这样,formEnhancement的每个实例都共享这些常用方法,并且任何继承formEnhancement的对象也都可以访问这些方法 – 2010-10-25 16:04:30

1

把函数命名空间:

声明这样说:

FormUtils = {}; 

,并添加它的属性,这将是你的职责

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

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

FormUtils.replaceSelect(); 

这是一个简单且非常接受的设计模式的JavaScript

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变量,该变量不能从外部,但可以通过库中的任何内容访问,这就是为什么我的示例中_selectBox这样的函数保持私有状态,但仍然可以通过库访问。选择框,这将是 “公共的getter”
[/编辑]

也,而不是

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

你可以做这样的事情:

var Library = Library || {}; 

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

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

var Library = Library || {}; 

在它们上面

的功能将被称为像这样:

Library.SelectBox(); 

,或在情况下,你选择去与 “子”

Library.UI.SelectBox();