Web组件:未调用setter

时间:2019-06-11 15:26:19

标签: javascript web-component

说我有一个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设置属性不会触发设置器,我部分可以理解。我的问题是:

  • 仅当我想以编程方式设置 properties 时,才需要二传手吗?
  • 如何对属性进行初始验证?在connectedCallback中?假设我只想接受某个字符串,我该如何检测呢?
  • 由于属性filter仍然被填充,如果我不使用JavaScript设置属性,是否需要设置器?

2 个答案:

答案 0 :(得分:2)

  • 仅当我想以编程方式设置属性时,才需要二传手吗?

是的,至少如果您希望/需要对要设置的值进行一些测试/过滤。

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

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

  • 由于无论如何都会填充属性过滤器,如果我不使用JavaScript设置属性,是否需要setter吗?

不,你不

这就是说,如果您需要对自定义属性的明确控制,我建议您创建一个内部状态,该状态在创建自定义元素时被填充一次,然后在调用attributeChangedCallback时填充一次。那会给你带来一些好处:

  • 您可以控制对自定义属性进行赋值的值。
  • 您将获得一个内部状态,可以在需要时使用它重新渲染组件

这里是一个例子:

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");

将对此感兴趣,以从社区中获得一些反馈。无论如何,希望这会有所帮助:)

答案 1 :(得分:1)

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

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

如果要在更改属性时运行代码,则需要添加attributeChangedCallback函数,并在observedAttributes静态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>

始终检查功能oldValnewValattributeChangedCallback是否不同。

还建议您在设置器中检查其他值。

设置程序还允许您采用特定的数据类型。例如,您可以检查value的值是否为数字,如果不是,则抛出TypeError

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

但是您必须记住,属性始终是字符串。属性可以是任何东西。