我有一个构造函数,它向我的文档中添加了一个计算器,每次都使用不同的类/ID,但当我尝试在构造函数内部、事件侦听器内部按类名访问这些元素时,我会得到null
。有什么想法吗?
我试图访问按钮3并"添加"
var calcDiv = document.createElement('div');
calcDiv.setAttribute('id', 'calcPage');
document.body.appendChild(calcDiv);
var calcList = [];
var calcID = 0;
document.getElementById("calcPage").innerHTML += '<table>' +
'<tr>' +
'<td><button type="button" class="addCalc" >Add Calculator</button></td>' +
'</tr>' +
'</table>';
//constructor for calculator
function calculator() {
var value = "";
this.id = calcID;
this.stringID = calcID.toString();
var calc = document.createElement('div');
calc.setAttribute('id', "calculator" + this.stringID);
calc.innerHTML =
'<table>' +
'<TR>' +
'<TD>' +
'<input class="buttonclr' + this.stringID + '" type="Button" value="clr">' +
'</TD>' +
'<TD colspan=3 align=middle>' +
'<input class="screen' + this.stringID + '" value="0" readonly>' +
'</TD>' +
'</TR>' +
'<TR>' +
'<TD>' +
'<input class="button-' + this.stringID + '" type="Button" value="-">' +
'</TD>' +
'<TD>' +
'<input class="button7' + this.stringID + '" type="Button" value="7">' +
'</TD>' +
'<TD>' +
'<input class="button8' + this.stringID + '" type="Button" value="8">' +
'</TD>' +
'<TD>' +
'<input class="button9' + this.stringID + '" type="Button" value="9">' +
'</TD>' +
'</TR>' +
'<TR>' +
'<TD>' +
'<input class="buttonadd' + this.stringID + '" type="Button" value="+">' +
'</TD>' +
'<TD>' +
'<input class="button4' + this.stringID + '" type="Button" value="4">' +
'</TD>' +
'<TD>' +
'<input class="button5' + this.stringID + '" type="Button" value="5">' +
'</TD>' +
'<TD>' +
'<input class="button6' + this.stringID + '" type="Button" value="6">' +
'</TD>' +
'</TR>' +
'<TR>' +
'<TD>' +
'<input class="button*' + this.stringID + '" type="Button" value="*">' +
'</TD>' +
'<TD>' +
'<input class="button1' + this.stringID + '" type="Button" value="1">' +
'</TD>' +
'<TD>' +
'<input class="button2' + this.stringID + '" type="Button" value="2">' +
'</TD>' +
'<TD>' +
'<input class="button3' + this.stringID + '" type="Button" value="3">' +
'</TD>' +
'</TR>' +
'<TR>' +
'<TD>' +
'<input class="button0' + this.stringID + '" type="Button" value="0">' +
'</TD>' +
'</TR>' +
'</table>';
calcDiv.appendChild(calc);
calcID++;
//press buttons event handling
var handle1 = function(event) {
value += '1';
//var screen =
alert(document.querySelector(".screen" + this.stringID).value);
//screen.value = eval(value+'0');
//screen.setAttribute("value",eval(value+'0').toString());
};
var button1 = document.querySelector(".button1" + this.stringID);
button1.addEventListener('click', handle1);
var handleAdd = function(event) {
value += '+';
var screen = document.querySelector("screen" + this.stringID);
screen.value = eval(value + '0')
//screen.ans.value = eval(value+'0');
//screen.setAttribute(value,eval(value+'0').toString());
};
var buttonAdd = document.querySelector(".buttonadd" + this.stringID);
buttonAdd.addEventListener('click', handleAdd);
}
//add event handling
var handleAddCalc = function(event) {
calcList.push(new calculator());
};
var addCalcu = document.querySelector(".addCalc");
addCalcu.addEventListener('click', handleAddCalc);
我是JavaScript和HTML的新手,所以并不是所有的东西都是最优的。。。
有几个问题。其中一些来自问题的早期版本(当答案引用了以前的代码时,更改问题中的代码并不理想)。
ID、类和集合
此行:
var screen = document.getElementById('screen' + this.stringID);
不起作用,因为你不是用id
创建元素,比如screen0
,你是用类创建元素,你可以这样选择:
var screen = document.querySelector('.screen' + this.stringID);
或者,使用它作为id
创建元素,原始的getElementById
就可以工作了。
这些线路:
var screen = document.getElementsByClassName("screen" + this.stringID);
screen.value = eval(value+'0');
不起作用,因为getElementsByClassName
返回所有匹配元素的集合,而不是单个元素,并且该集合没有value
属性。相反,再次使用querySelector
,它只返回第一个匹配元素:
var screen = document.querySelector('.screen' + this.stringID);
screen.value = eval(value+'0');
(此外,getElementsByClassName
不如querySelector
及其表亲querySelectorAll
得到很好的支持,后者像getElementsByClassName
一样返回一个集合。例如,IE8没有getElementsByClassName
,但有QS/QSA。遗憾的是,IE8在全球市场份额超过10%,但希望不会持续太久。)
有时您也会错过.
,例如handleAdd
:中的这一行
var screen = document.querySelector("screen" + this.stringID);
// Missing . ------------------------^
this
第二个问题是您没有在回调中保留this
的值,因此:
button1.addEventListener('click', handle1);
单击按钮时将设置对handle1
的回调,但在回调中,this
将是对button1
元素的引用,而不是对计算器实例的引用。
您可以使用Function#bind
创建一个新函数,当调用该函数时,该函数将使用正确的this
:调用handle1
button1.addEventListener('click', handle1.bind(this));
或者,由于所有这些都在构造函数中,您可以在构造函数中使用一个局部变量,将其设置为this
(在顶部一次通常是最好的):
var thisCalc = this;
然后使用匿名函数:
button1.addEventListener('click', function() {
handle1.call(thisCalc);
});
但是Function#bind
选项简单易用。
带有一些修复程序的代码段
以下是修复上述问题的片段:
var calcDiv = document.createElement('div');
calcDiv.setAttribute('id', 'calcPage');
document.body.appendChild(calcDiv);
var calcList = [];
var calcID = 0;
document.getElementById("calcPage").innerHTML += '<table>' +
'<tr>' +
'<td><button type="button" class="addCalc" >Add Calculator</button></td>' +
'</tr>' +
'</table>';
//constructor for calculator
function calculator() {
var value = "";
this.id = calcID;
this.stringID = calcID.toString();
var calc = document.createElement('div');
calc.setAttribute('id', "calculator" + this.stringID);
calc.innerHTML =
'<table>' +
'<TR>' +
'<TD>' +
'<input class="buttonclr' + this.stringID + '" type="Button" value="clr">' +
'</TD>' +
'<TD colspan=3 align=middle>' +
'<input class="screen' + this.stringID + '" value="0" readonly>' +
'</TD>' +
'</TR>' +
'<TR>' +
'<TD>' +
'<input class="button-' + this.stringID + '" type="Button" value="-">' +
'</TD>' +
'<TD>' +
'<input class="button7' + this.stringID + '" type="Button" value="7">' +
'</TD>' +
'<TD>' +
'<input class="button8' + this.stringID + '" type="Button" value="8">' +
'</TD>' +
'<TD>' +
'<input class="button9' + this.stringID + '" type="Button" value="9">' +
'</TD>' +
'</TR>' +
'<TR>' +
'<TD>' +
'<input class="buttonadd' + this.stringID + '" type="Button" value="+">' +
'</TD>' +
'<TD>' +
'<input class="button4' + this.stringID + '" type="Button" value="4">' +
'</TD>' +
'<TD>' +
'<input class="button5' + this.stringID + '" type="Button" value="5">' +
'</TD>' +
'<TD>' +
'<input class="button6' + this.stringID + '" type="Button" value="6">' +
'</TD>' +
'</TR>' +
'<TR>' +
'<TD>' +
'<input class="button*' + this.stringID + '" type="Button" value="*">' +
'</TD>' +
'<TD>' +
'<input class="button1' + this.stringID + '" type="Button" value="1">' +
'</TD>' +
'<TD>' +
'<input class="button2' + this.stringID + '" type="Button" value="2">' +
'</TD>' +
'<TD>' +
'<input class="button3' + this.stringID + '" type="Button" value="3">' +
'</TD>' +
'</TR>' +
'<TR>' +
'<TD>' +
'<input class="button0' + this.stringID + '" type="Button" value="0">' +
'</TD>' +
'</TR>' +
'</table>';
calcDiv.appendChild(calc);
calcID++;
//press buttons event handling
var handle1 = function(event) {
value += '1';
//var screen =
alert(document.querySelector(".screen" + this.stringID).value);
//screen.value = eval(value+'0');
//screen.setAttribute("value",eval(value+'0').toString());
};
var button1 = document.querySelector(".button1" + this.stringID);
button1.addEventListener('click', handle1.bind(this));
var handleAdd = function(event) {
value += '+';
var screen = document.querySelector(".screen" + this.stringID);
screen.value = eval(value + '0')
//screen.ans.value = eval(value+'0');
//screen.setAttribute(value,eval(value+'0').toString());
};
var buttonAdd = document.querySelector(".buttonadd" + this.stringID);
buttonAdd.addEventListener('click', handleAdd.bind(this));
}
//add event handling
var handleAddCalc = function(event) {
calcList.push(new calculator());
};
var addCalcu = document.querySelector(".addCalc");
addCalcu.addEventListener('click', handleAddCalc.bind(this));
附带说明:id
属性在元素实例上有一个反射属性,因此这是:
calc.setAttribute('id', "calculator" + this.stringID);
可以是简单的
calc.id = this.stringID;