首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >初始化CustomElement移除类方法(get/ set ),如果属性在定义元素之前具有相同的名称集

初始化CustomElement移除类方法(get/ set ),如果属性在定义元素之前具有相同的名称集
EN

Stack Overflow用户
提问于 2019-09-06 00:30:27
回答 1查看 452关注 0票数 0

自定义元素可以异步初始化,例如在延迟加载其定义类之后。

让我们看一下这个例子,我们在DOM中有一个元素还没有初始化:

代码语言:javascript
运行
复制
<component-with-async-init></component-with-async-init>

初始化之前,我们设置此元素的value属性:

代码语言:javascript
运行
复制
querySelector('component-with-async-init').value = "GETTERS SETTERS ARE KILLED"

然后,通过将该元素定义为自定义元素来导入该元素。如您所见,它的定义类有getter和setter用于value属性。

代码语言:javascript
运行
复制
class ComponentWithAsyncInit extends HTMLElement{
    static get is() {
        return 'component-with-async-init'
    }
    get value(){
        console.log("Getting value")
        return "VALUE FROM GETTER"
    }
    set value(v){
        console.log("Setting value")
    }
}

window.customElements.define(ComponentWithAsyncInit.is, ComponentWithAsyncInit);

Getter和setter(或任何方法)现在都会被杀死,如您所见:

代码语言:javascript
运行
复制
querySelector('component-with-async-init').value //"GETTERS SETTERS ARE KILLED"

我在最新的Safari、Firefox和Chrome浏览器中观察到了这种行为,其他的都没有经过测试。这个问题影响聚合物和发光元素库以及纯定制元素。似乎在每个浏览器中都是这样工作的。

问题:这真的是一种预期的行为吗?如果在元素定义之前设置了属性,那么Getters和Setters以及任何方法都会被清除。如果是,什么是解决办法,因为我们通常无法控制什么时候设置元素值

片段:

代码语言:javascript
运行
复制
document.querySelector('component-with-async-init').value = "SETTERS GETTERS KILLED"
document.querySelector('component-with-async-init').getSomeValue = "GET SOME VALUE KILLED"

class ComponentWithAsyncInit extends HTMLElement{
    static get is() {
        return 'component-with-async-init'
    }
    get value(){
        console.log("Getting value")
        return "VALUE FROM GETTER"
    }
    set value(v){
        console.log("Setting value")
    }

    getSomeValue(){
        return "SOME VALUE"
    }
}

window.customElements.define(ComponentWithAsyncInit.is, ComponentWithAsyncInit);
console.log("getSomeValue method:")
console.log(document.querySelector('component-with-async-init').getSomeValue)            
console.log("Reading value:")
console.log(document.querySelector('component-with-async-init').value)
代码语言:javascript
运行
复制
<component-with-async-init></component-with-async-init>

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-09-06 03:34:25

这确实是意料之中的。HTML规范要求当创建CustomElement时

  1. 执行element.[[SetPrototypeOf]](prototype)

它是来自ECMAScript标准的,它只设置element将继承的[[Prototype]]。这样做不会覆盖自己的属性值。

代码语言:javascript
运行
复制
const elem = { a: "my own a" };
Object.setPrototypeOf(elem, { a: "proto's a", b: "proto's b" });
console.log(elem.a) // "my own a"
console.log(elem.b) // "proto's b"

您可以尝试通过再次显式设置已重写的属性来解决这一问题,然后重新设置值,以便调用setter,

代码语言:javascript
运行
复制
document.querySelector('component-with-async-init').value = "SETTERS GETTERS KILLED";
document.querySelector('component-with-async-init').getSomeValue = "GET SOME VALUE KILLED";

class ComponentWithAsyncInit extends HTMLElement {
  constructor() {
    super();
    // first grab the properties that might already have been set
    const ownProps = Object.entries(this);
    // our class's prototype
    const proto = ComponentWithAsyncInit.prototype;
    // get all properties descriptors
    const proto_desc = Object.getOwnPropertyDescriptors(proto);

    ownProps.forEach(([key, value]) => {
      // got overriden
      if (key in proto_desc) {
        // apply the one from our class
        Object.defineProperty(this, key, proto_desc[key]);
        // set again the own property (call setters)
        this[key] = value;
      }
    });
  }
  static get is() {
    return 'component-with-async-init'
  }
  get value() {
    console.log("Getting value")
    return "VALUE FROM GETTER"
  }
  set value(v) {
    console.log("Setting value")
  }

  getSomeValue() {
    return "SOME VALUE"
  }
}

window.customElements.define(ComponentWithAsyncInit.is, ComponentWithAsyncInit);
customElements.upgrade(document.querySelector('component-with-async-init'))
console.log("getSomeValue method:")  // note that this will get overidden anyway
console.log(document.querySelector('component-with-async-init').getSomeValue)
console.log("Reading value:")
console.log(document.querySelector('component-with-async-init').value)
代码语言:javascript
运行
复制
<component-with-async-init></component-with-async-init>

但是这听起来很难看,而且在初始化方法调用之前不会阻止它们。

因此,最好的方法是在使用这些元素之前等待元素的注册。

代码语言:javascript
运行
复制
customElements.whenDefined("component-with-async-init")
  .then(() => {
    document.querySelector('component-with-async-init').value = "SETTERS GETTERS KILLED"
    document.querySelector('component-with-async-init').getSomeValue = "GET SOME VALUE KILLED"
    console.log("getSomeValue method:") // note that this will get overidden anyway
    console.log(document.querySelector('component-with-async-init').getSomeValue)            
    console.log("Reading value:")
    console.log(document.querySelector('component-with-async-init').value)
  });
class ComponentWithAsyncInit extends HTMLElement{
    static get is() {
        return 'component-with-async-init'
    }
    get value(){
        console.log("Getting value")
        return "VALUE FROM GETTER"
    }
    set value(v){
        console.log("Setting value")
    }

    getSomeValue(){
        return "SOME VALUE"
    }
}

window.customElements.define(ComponentWithAsyncInit.is, ComponentWithAsyncInit);
代码语言:javascript
运行
复制
<component-with-async-init></component-with-async-init>

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57814360

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档