无法访问javascript中的元素(null)



我有一个构造函数,它向我的文档中添加了一个计算器,每次都使用不同的类/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;

最新更新