今天把自己给坑了,在大型Nodejs项目中,你能看出来坑在哪里吗?

今天把自己给坑了,在大型Nodejs项目中,你能看出来坑在哪里吗?

以下情况,#demo1 永远不会变色,知道为什么吗?

这个把我坑惨了,在复杂的构造函数中很难找出原因,也说明了基础很重要,哦不,实战更重要。

javascript版

var Test1, demo1;

Test1 = (function() { function Test1(el) { this.el = el; this.set1(); this.set2(); }

Test1.prototype.set1 = function() { var p; p = “<p>这是一个测试</p>”; return document.body.innerHTML += p; };

Test1.prototype.set2 = function() { return this.el.style.background = ‘blue’; };

return Test1;

})();

demo1 = new Test1(document.querySelector(’#demo1’));

coffee版

class Test1
    constructor: (el) ->
        @el   = el
        @set1()
        @set2()
        
    set1: ->
        p = """<p>这是一个测试</p>"""
        document.body.innerHTML += p
        
    set2: ->
        @el.style.background = 'blue'
        
demo1 = new Test1 document.querySelector('#demo1')

7 回复

今天把自己给坑了,在大型Node.js项目中,你能看出来坑在哪里吗?

在这个问题中,我遇到了一个常见的陷阱。这个问题出现在JavaScript和CoffeeScript版本的代码中。具体来说,#demo1元素永远不会变色。这是为什么呢?

JavaScript 版本

var Test1, demo1;

Test1 = (function() {
  function Test1(el) {
    this.el = el;
    this.set1();
    this.set2();
  }

  Test1.prototype.set1 = function() {
    var p;
    p = "<p>这是一个测试</p>";
    return document.body.innerHTML += p;
  };

  Test1.prototype.set2 = function() {
    return this.el.style.background = 'blue';
  };

  return Test1;

})();

demo1 = new Test1(document.querySelector('#demo1'));

CoffeeScript 版本

class Test1
    constructor: (el) ->
        @el   = el
        @set1()
        @set2()
        
    set1: ->
        p = """<p>这是一个测试</p>"""
        document.body.innerHTML += p
        
    set2: ->
        @el.style.background = 'blue'
        
demo1 = new Test1 document.querySelector('#demo1')

问题分析

在这两个版本的代码中,问题在于 document.body.innerHTML += p 这一行。

当我们在JavaScript中使用 innerHTML 属性时,它会解析HTML字符串并替换当前节点的子节点。这意味着如果你在 innerHTML 中添加新的内容,浏览器会将所有内容重新解析,并且任何现有的DOM节点都会被移除并重新创建。

因此,当你调用 set1() 方法时,#demo1 元素的背景颜色设置操作(即 this.el.style.background = 'blue')在重新解析过程中被删除了。这导致 #demo1 元素的背景颜色从未被正确设置。

解决方案

为了避免这种情况,你可以使用 insertAdjacentHTML 方法来插入新的HTML内容,而不是直接修改 innerHTML。这样可以避免整个节点树被重新解析。

Test1.prototype.set1 = function() {
  var p;
  p = "<p>这是一个测试</p>";
  this.el.insertAdjacentHTML('beforeend', p);
};

或者在CoffeeScript中:

set1: ->
    p = """<p>这是一个测试</p>"""
    @el.insertAdjacentHTML('beforeend', p)

通过这种方式,你可以在不破坏现有DOM结构的情况下,向 #demo1 元素中添加新的HTML内容。


看不懂。。

是不是你在用innerHTML的时候刷新了dom树,重新生成了 #demo1啊。。。 看到你贴了这两个版本,还以为是构造函数的坑呢

看到document.body.innerHTML感觉挺突兀的,改成this.el.innerHTML就好了。

第一个set1把body内容都换掉了

document.body.innerHTML += p;

在这个例子中,#demo1 永远不会变色的原因在于 document.body.innerHTML += p; 这行代码。这行代码会将新的 HTML 内容追加到 document.body 中,导致 document.querySelector('#demo1') 找不到元素,因为 #demo1 已经被覆盖或移除。

具体来说,当你在 document.body.innerHTML 中添加新的内容时,浏览器会重新解析整个 body 的内容,从而可能导致原来的 #demo1 被新内容替换或覆盖,因此 this.el 变成了一个不存在的元素。

示例代码

// 修改后的 JavaScript 版本
var Test1, demo1;

Test1 = (function() {
  function Test1(el) {
    this.el = el;
    if (this.el) { // 确保 el 存在
      this.set1();
      this.set2();
    }
  }

  Test1.prototype.set1 = function() {
    var p;
    p = "<p>这是一个测试</p>";
    // 使用 insertAdjacentHTML 代替 innerHTML
    document.body.insertAdjacentHTML('beforeend', p);
  };

  Test1.prototype.set2 = function() {
    if (this.el) {
      this.el.style.background = 'blue';
    }
  };

  return Test1;

})();

demo1 = document.querySelector('#demo1');
if (demo1) {
  new Test1(demo1);
}

解释

  • 使用 insertAdjacentHTMLinsertAdjacentHTML 是一种更安全的方式来插入 HTML 内容,因为它不会重写整个 body 的内容。
  • 检查元素是否存在:在调用 set2 方法之前,先检查 this.el 是否存在,以确保不会对不存在的元素进行操作。

这样修改后,#demo1 应该能够正确变色。

回到顶部