2014-03-03 163 views
0

舊時代的OO程序員,新的JavaScript/html編碼。Javascript類生成HTML按鈕:如何實現`this`上的閉包?

所以我正在玩JavaScript的「類」,試圖製作一個可重複使用的單元,將自己寫入html。

<html> 
<script> 
function Foo(min_input, max_input) { 
    var n_min_input = min_input; 
    var n_input = max_input; 
    var curr_shown = min_input; 
    this.show_one_more = function() { 
     if (curr_shown < n_input) { 
      document.getElementById('input' + curr_shown).style = 'display: block'; 
      curr_shown++; 
     } 
    } 
    this.show_one_less = function() { 
     if (curr_shown > n_min_input) { 
      curr_shown--; 
      document.getElementById('input' + curr_shown).style = 'display: none'; 
     } 
    } 
    this.write_inputs = function() { 
     for (var i = 0; i < n_min_input; i++) { 
      document.write("<input type='text' style='display: block' value='" + i + "' id='input" + i + "' name='input" + i + "'/>"); 
     } 
     for (var i = n_min_input; i < n_input; i++) { 
      document.write("<input type='text' style='display: none' value='" + i + "' id='input" + i + "' name='input" + i + "'/>"); 
     } 
     //want to essentially do this, but don't know how 
     document.write("<p><input type='button' onclick='this.show_one_more()' value='+'></input><input type='button' value='-' onclick='this.show_one_less()'/></p>"); 
    } 
} 
var f = new Foo(1, 5); 
f.write_inputs(); 
//works here, but would rather it be generated in f.write_inputs(); 
document.write("<p><input type='button' onclick='this.show_one_more()' value='+'></input><input type='button' value='-' onclick='this.show_one_less()'/></p>"); 
</script> 
<input type="button" value="stuff" id="sbutton"/> 
</html> 

所以基本上,我想在按鈕上的文檔編寫調用中得到某種封閉。我覺得這是人們以前可能用過的模式(但我可能完全錯誤)。我的想法:

使全局變量var foo_idx=0和數組var allfoos = [];。在初始化(類的主體)做this.foo_idx=foo_idx; allfoos[foo_idx]=this;foo_idx++,然後我可以使用allfoos[foo_idx]來捕獲這個。但感覺哈克。人們通常如何創建可重用的html元素?

+5

首先,也是最重要的一點:__DROP__'document.write'。它只能用於在頁面加載時將內容寫入當前文檔 - 之後對其進行的任何調用(如從函數內部)_overwrites_當前文檔。閱讀如何使用DOM方法創建元素,或者使用'.innerHTML',或者 - 不要重新發明輪子,而是使用一個庫,而不是已經有更復雜的DOM操作方法的庫。 – CBroe

回答

1

除非我在這裏誤解了你的需要,只需將它保存到一個變量:

function Foo(min_input, max_input) { 
    // save a reference to "this" to be used in anonymous function 
    var that = this; 

    this.show_one_more = function() { 
     // can use "that" here to reference the outer "this" 
    } 
} 

重讀你的代碼的註釋,你將需要溝document.write(也許應該是這樣),並直接與DOM工作元素,而不是一個字符串。然後,你可以做這樣的事情:

var input = document.createElement("input"); 
input.type = "button"; 
input.value = "+"; 

// on click, call the outer object's function 
input.onclick = that.show_one_more; 

container.appendChild(input); 

基本概念的演示:http://jsfiddle.net/SaLvE/

+0

不需要使用'that = this'這個技巧。你可以簡單地使用'.bind'來修飾上下文。 –

+0

@BenjaminGruenbaum是的,在這種情況下,這將工作得很好,因爲沒有使用該函數自己的'this'。 –

0

你會過得更好結合回調函數所創建的元素的onclick處理程序。通常認爲它是在HTML標籤上寫出顯式事件處理程序的反模式。

此外,如果您創建了實際的DOM對象而不是使用document.write將html寫爲字符串,則可以創建對這些DOM對象的引用。

這裏是沿着什麼,我推測會去的地方,你的評論作爲//行線的東西要基本做到這一點:

//You will need a parent DOM element to insert into. Defaulting to <body> (your example is actually missing this basic html tag) 
var parentContainer = document.getElementsByTagName('body')[0]; 

var newParagraph = document.createElement('p'); 
var newButton1 = document.createElement('input'); 
var newButton2 = document.createElement('input'); 

newButton1.type='button' 
newButton2.type='button' 

newButton1.value='+' 
newButton2.value='-' 

newButton1.addEventListener('click', this.show_one_more,false); 
newButton2.addEventListener('click', this.show_one_less,false); 

newParagraph.appendChild(newButton1); 
newParagraph.appendChild(newButton2); 
parentContainer.appendChild(newParagraph); 

雖然不相關的show_one_more和show_one_less函數,值得指出的是,在這種情況下,這些函數內部的值this最終將解析爲按鈕的DOM元素而不是Foo對象實例。

這是因爲DOM元素成爲事件處理程序的調用者和onclick回調的調用,因此變成this。如果你想避免這種情況,並有this仍引用Foo對象實例,然後你可以使用bind功能如下:

newButton1.addEventListener('click', this.show_one_more.bind(this),false); 
newButton2.addEventListener('click', this.show_one_less.bind(this),false); 
相關問題