2010-10-25 88 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();