【问题标题】:Defining multiple custom attributes on a custom HTML Element在自定义 HTML 元素上定义多个自定义属性
【发布时间】:2021-07-31 19:44:08
【问题描述】:

为自定义 HTML 元素的自定义属性添加 getter/setter 非常简单:

  customElements.define('custom-el', class extends HTMLElement {
    
    static get observedAttributes() {
      return ['customAttr']
    }

    get customAttr() {
      return this.getAttribute('customAttr')
    }

    set customAttr(value) {
      this.setAttribute('customAttr', value)
    }

    constructor() {
      super();
    }
    
  })

但是,如果您在同一个元素上有多个自定义属性,这会变得非常麻烦:

  customElements.define('custom-el', class extends HTMLElement {
    
    static get observedAttributes() {
      return ['customAttr1', 'customAttr2', 'customAttr3']
    }

    // for attr 1

    get customAttr1() {
      return this.getAttribute('customAttr1')
    }

    set customAttr1(value) {
      this.setAttribute('customAttr1', value)
    }

    // for attr 2

    get customAttr2() {
      return this.getAttribute('customAttr2')
    }

    set customAttr2(value) {
      this.setAttribute('customAttr2', value)
    }

    // for attr 3

    get customAttr3() {
      return this.getAttribute('customAttr3')
    }

    set customAttr3(value) {
      this.setAttribute('customAttr3', value)
    }

    constructor() {
      super();
    }
    
  })

我一直在考虑如何编写一个函数,该函数将从一组自定义属性名称中生成 getter/setter,但如果不能将变量字符串作为 get 的名称传递,这似乎是不可能的/设置。

documentation for "getter" 表明方括号中的表达式是可以接受的,这适用于一个变量字符串:

const x = "customAttr";

customElements.define('custom-el', class extends HTMLElement {
    
  static get observedAttributes() {
    return x;
  }

  get [x]() {
    return this.getAttribute(x)
  }

  set [x](value) {
    this.setAttribute(x, value)
  }

  constructor() {
    super(); 
  }

})
<custom-el customAttr="It works"></custom-el>
console.log(document.querySelector("custom-el").customAttr) // yields "It works"

不幸的是,自定义元素定义的主体中不允许 for/forEach 循环(在嵌入式子例程之外,此时 get/set 操作不再起作用!):

const customAttrs = ["customAttr1", "customAttr2", "customAttr3"];

customElements.define('custom-el', class extends HTMLElement {
    
  static get observedAttributes() {
    return customAttrs;
  }

  customAttrs.forEach( customAttr => {
    get [customAttr]() {
      return this.getAttribute(customAttr)
    }

    set [customAttr](value) {
      this.setAttribute(customAttr, value)
    }
  })

  constructor() {
    super(); 
  }

})
<custom-el customAttr1="It " customAttr2="doesn't " customAttr3="work"></custom-el>
let customEl = document.querySelector("custom-el");
console.log(testEl.customAttr1+testEl.customAttr2+testEl.customAttr3) // yields error

如果自定义 HTMLElement 类有一个“defineAttribute”方法,其操作类似于对象的“defineProperty”,您可以执行以下操作:

const customEl = ...

const customAttrs = ["customAttr1", "customAttr2", "customAttr3", ...]

customAttrs.forEach( customAttr => {
  HTMLElement.defineAttribute(customEl, customAttr, {
    get : function(){ return this.getAttribute(customAttr ); },
    set : function(newValue){ this.setAttribute(customAttr, newValue); }
  }
}

...但似乎不存在这样的东西。

tl;dr - 真的没有比为每个元素编写 set/get 定义更好的方法来为自定义元素上的自定义属性设置多个 setter/getter 吗?

【问题讨论】:

    标签: javascript html ecmascript-6 web-component custom-tags


    【解决方案1】:

    使用Object.defineProperty( element , attrName , { getter , setter , options} )

    类似的东西添加到您的 BaseClass(所以 this 是您的自定义元素)

      defineProperty(
        attr,
        getter = (attr) => this.getAttribute(attr),
        setter = (val, attr) => (val == undefined ? this.removeAttribute(attr) : this.setAttribute(attr, val)),
        options = {
          configurable: true,
        }
      ) {
        return Object.defineProperty(this, attr, {
          get() {
            return getter(attr);
          },
          set(val) {
            return setter(val, attr);
          },
          ...options,
        });
      }
    
    

    参见:

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

    复数:

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties

    【讨论】:

    • 感谢您的回复!我对 Object.defineProperty/Object.defineProperties 很熟悉,因为它们用于对象,但我不太确定我是否理解你在这里实现它的意思。这应该以“Object.”为前缀吗?你的意思是我应该定义一个也叫“defineProperty”的新函数?
    • 不管你给它起什么名字;这是(BaseClass)元素上的方法,所以用法是:this.defineProperty 你想要HTMLElement.defineAttribute
    • 好的,我想我已经明白你的意思了。我还不太习惯默认参数,所以我认为这让我感到困惑。 Nogmaals bedankt voor je hulp!
    • 是的,标准参数 zijn zeer krachtig.. JavaScript 很酷
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-22
    • 2017-06-02
    • 2019-12-11
    • 2021-01-26
    • 1970-01-01
    相关资源
    最近更新 更多