Javascript: 在class里面赋值onclick

Javascript: assign onclick inside class

我创建了一个构造函数来处理自定义列表控件。我创建了一个方法来允许用户向列表中添加元素,我需要为列表元素 (divs) 的点击事件分配事件处理程序。

这里是代码的简化版本。列表元素是使用 innerHTML 属性 和我在其上替换特定部分的字符串模板创建的。后来我通过它的 id 获取元素并在闭包中为它分配一个函数:

function prueba(){
    var plantilla = '<div id="«id»">«texto»</div>';

    var f = function(nombre){
        return function(){console.log('mi nombre es ' + nombre)};
    };

    this.agregar = function(id, texto){
        var tmp = plantilla.replace('«id»', id);
        tmp = tmp.replace('«texto»', texto);
        document.body.innerHTML += tmp;

        document.getElementById(id).onclick = f(id);
    };
};

问题是,显然,事件处理程序未分配给先前创建的 div,因此仅由最后一个保留,因为可以使用以下代码进行测试:

var p = new prueba;

p.agregar('i1', 'texto1');
console.log(document.getElementById('i1').onclick.toString());//shows the function code
p.agregar('i2', 'texto2');
console.log(document.getElementById('i2').onclick.toString());//shows the function code
console.log(document.getElementById('i1').onclick.toString());//returns 'null' error
p.agregar('i3', 'texto3');
console.log(document.getElementById('i3').onclick.toString());//shows the function code
console.log(document.getElementById('i2').onclick.toString());//returns 'null' error

这发生在 Iceweasel 和 Chromium 中。当我在模板中添加 'onclick = f(«id»)' 时它不会发生(由于分配的函数范围我不能在这里这样做),如果我使用 document.createElement 也不会发生。我做错了什么?

这样做会破坏之前创建的元素:

document.body.innerHTML += tmp;

如果您想使用 HTML 标记附加,请改用 insertAdjacentHMTL()

document.body.insertAdjacentHTML("beforeend", tmp);

现在不要经历这个破坏性的过程...

  1. 将现有的DOM个节点序列化为HTML
  2. 将新的 HTML 片段连接到序列化节点
  3. 销毁旧节点
  4. 用新节点重新创建节点

...它只是创建新内容并将其放置在 body 元素结束之前。

基本上,从您的编码实践中删除 element.innerHTML += ...。从来没有必要,它效率低下并且会导致您所描述的问题。


仅供参考,.insertAdjacentHTML() 方法接收 4 种不同的字符串可能性作为第一个参数。每个都指定一个相对于您调用它的元素的位置。

字符串是...

  • "beforebegin"
  • "afterbegin"
  • "beforeend"
  • "afterend"

这些标签是不言自明的。它们分别将新内容定位在当前元素之前、在当前元素的开头、在当前元素的结尾或在当前元素之后。


您的完整代码如下所示,我也缩短了一点,因为这里确实不需要 tmp

function prueba(){
    var plantilla = '<div id="«id»">«texto»</div>';

    var f = function(nombre){
        return function(){console.log('mi nombre es ' + nombre)};
    };

    this.agregar = function(id, texto){
        document.body.insertAdjacentHTML("beforeend",
                                             plantilla.replace('«id»', id)
                                                      .replace('«texto»', texto));

        document.getElementById(id).onclick = f(id);
    };
};