3

我最近一直在使用 HTML5 自定义元素,偶然发现了一个令人沮丧的问题。在所有示例中考虑以下 HTML 正文:

<body>
    <h2>Foo elements.</h2>
    <foo-element>One!</foo-element>
    <foo-element>Two!</foo-element>
</body>

这个脚本附加到页面的头部,用于注册自定义元素:

var HTMLFooElement = document.registerElement('foo-element', {
  prototype: Object.create(HTMLDivElement.prototype, {
    createdCallback: { value: function() {
      console.log('[CALLBACK] created: ', this);
    }},
    attachedCallback: { value: function() {
      console.log('[CALLBACK] attached: ', this);
    }}
  })
});

该应用程序将在 Chromium 版本 41.0.2272.76 上按预期工作:声明的自定义元素将触发两个回调,将 4 行打印到控制台。

[CALLBACK] created: <foo-element>One!</foo-element> [CALLBACK] attached: <foo-element>One!</foo-element> [CALLBACK] created: <foo-element>Two!</foo-element> [CALLBACK] attached: <foo-element>Two!</foo-element>

但是现在我有这个用例,我必须将定义推迟attachedCallback到未来的场合:

var HTMLFooElement = document.registerElement('foo-element', {
  prototype: Object.create(HTMLDivElement.prototype, {
    createdCallback: { value: function() {
      console.log('[CALLBACK] created: ', this);
    }},
  })
});
HTMLFooElement.prototype.attachedCallback = function() {
  console.log('[CALLBACK] attached: ', this);
};

事实证明,此版本不会触发attachedCallback,并且不会打印“附加”日志行(jsfiddle)。此时,该函数肯定会在我的所有自定义元素中作为成员,因为所有代码都是在body处理 DOM 部分之前执行的。不管怎样,在加载文档后在 JavaScript 中创建和附加新元素时,结果是相同的。

令我感到困惑的是,在注册自定义标签后生命周期回调的后期定义没有被应用。我应该怎么做才能在调用后定义一个生命周期回调registerElement并使其真正生效?

4

1 回答 1

1

注册元素的过程似乎在内部复制了每个生命周期回调,这意味着修改原始原型没有任何效果。我设法避免在我的项目中重新定义,但对于那些遇到同样问题的人来说,引入代理是解决它的一种方法,它不涉及重新注册元素。

var protoProxy = {
    createdCallback: function(e) {
        console.log('[CALLBACK] created: ', e);
    },
    attachedCallback: function(e) {
      console.log('[CALLBACK] placeholding ...');
    }
};
var HTMLFooProto = Object.create(HTMLDivElement.prototype, {
  createdCallback: { value: function() {
      protoProxy.createdCallback(this);
  }},
  attachedCallback: { value: function() {
      protoProxy.attachedCallback(this);
    }}
});

var HTMLFooElement = document.registerElement('foo-element', {
  prototype: HTMLFooProto
});

protoProxy.attachedCallback = function(e) {
  console.log('[CALLBACK] attached: ', e);
};

jsFiddle

于 2015-03-30T10:32:45.007 回答