Web 组件:setter 未被调用

Web Components: setter not being called

假设我有一个 Web 组件:

customElements.define("custom-list", class CustomList extends HTMLElement {
  get filter() {
    console.log("get filter");
    return this.getAttribute("filter");
  }

  set filter(value) {
    console.log("set filter");
    this.setAttribute("filter", value);
  }
});

我想使用 setter 方法进行一些初始属性验证,但从未调用 setter。我尝试通过 HTML:

设置属性
<custom-list filter="some value"></custom-list>

只有当我使用 JavaScript 以编程方式设置 属性 时,才会调用 setter:

var list = document.querySelector("custom-list");
list.filter = "some value";

list.setAttribute("filter", "some value"); // DOESN'T WORK EITHER

所以,似乎通过HTML设置属性或使用setAttribute不会触发setter,我能部分理解。我的问题是:

  • 只有当我想以编程方式设置属性时才需要 setter 吗?

是的,至少如果您 want/need 到 运行 一些 tests/filtering 要设置的值。

  • 如何对属性进行初始验证?在 connectedCallback 中?假设我只想接受某个字符串,我该如何检测?

是的,connectedCallback 甚至在构造函数中。

  • 既然 属性 过滤器无论如何都会被填充,如果我不使用 JavaScript 来设置我的属性,我还需要 setter 吗?

不,你没有

也就是说,如果您需要对自定义属性进行明确控制,我建议创建一个内部状态,在创建自定义元素时填充一次,然后在调用 attributeChangedCallback 时填充一次。那会给你一些优势:

  • 您可以控制为您的自定义属性赋值的值。
  • 你得到了一个内部状态,如果你需要
  • ,你可以用它来 re-render 你的组件

这是一个例子:

customElements.define("custom-list", class CustomList extends HTMLElement {

    static get observedAttributes() { return ['filter']; }

    constructor() {
        super();
        this.state = {
            filter: null
        };
        this.setFilter(this.getAttribute("filter"));
    }

    attributeChangedCallback(name, oldValue, newValue) {
        if (name === "filter") {
            this.setFilter(newValue);
        }
    }

    getFilter() {
        console.log("get filter");
        return this.state.filter;
    }

    setFilter(value) {
        // You can add some logic here to control the value
        console.log("set filter");
        this.state.filter=value;
    }
});

然后你可以调用下面的代码来改变你的内部状态:

list.setAttribute("filter", "some value");

很想从社区获得一些对此的反馈。无论如何,希望这会有所帮助:)

getters 和 setter 允许您的代码接收字符串以外的值。属性始终是字符串,只能由 JavaScript.

调用

您可以通过解析值来模拟属性中的 non-string。但它们总是作为字符串传入。

如果您想在更改属性时使用代码 运行,则需要添加 attributeChangedCallback 函数并在 observedAttributes static getter。可以通过调用 setAttributeremoveAttribute 在 JavaScript 中设置属性。当浏览器由于页面加载或设置 innerHTML 解析您的 HTML 时,也会设置它们。但即便如此,浏览器最终还是会在后台调用 setAttribute

customElements.define("custom-list", class CustomList extends HTMLElement {
  static get observedAttributes() { return ['filter']; }

  constructor() {
    super();
    this._filter = null;
  }

  attributeChangedCallback(attr, oldVal, newVal) {
    if (oldVal != newVal) {
      // Only set this value if it is different
      this.filter = newVal;
    }
  }

  get filter() {
    console.log("get filter");
    return this._filter;
  }

  set filter(value) {
    if (value !== this._filter) {
      console.log(`set filter ${value}`);
      this._filter=value;
      this.textContent = value;
      // If you want the filter property to always show
      // in the attributes then do this:
      if (value !== null) {
        this.setAttribute('filter', value);
      } else {
        this.removeAttribute('filter');
      }
    }
  }
});

const el = document.querySelector('custom-list');
setTimeout(() => {
  el.filter = 'happy';
}, 2000);
<custom-list filter="10"></custom-list>

始终 检查您的 oldValnewVal 在函数 attributeChangedCallback.

中是否不同

还建议您检查设置器中的不同值。

Setter 还允许您获取特定的数据类型。例如,您可以检查 value 的值是否为数字,如果不是,则抛出 TypeError.

设置器还允许您确保值有效。也许它必须是正数或三个可能的字符串之一。如果不是,你可以抛出一个 RangeError.

但是你必须记住属性总是字符串。属性可以是任何东西。