资讯专栏INFORMATION COLUMN

使用 custom element 创建自定义元素

timger / 3340人阅读

摘要:通过创建元素时也有不同也可以直接调用构造函数创建注直到版本,扩展内置元素依然在开发中。自定义元素被移入新的时调用。

很早我们就可以在 HTML 文档中写 这样的自定义名称标签。但是浏览器对于不认识的标签一律当成一个普通的行内元素处理,没有相关语义。虽然我们能用 JavaScript 代码给它添加一些功能,但是并没有生命周期相关的函数供我们做一些初始化和销毁的处理。

通过浏览器提供的 Custom elements api 我们能定义一个自定义元素,并且告知 HTML 解析器如何正确地构造一个元素,以及在该元素的属性变化时执行相应的处理。

定义新元素

比如我们想要像 这样使用一个显示日期字符串的标签,并且在 ln 属性为 zh 时显示中文格式,en 时显示英文格式。

首先我们定义一个类 DateString 派生自 HTMLElement。

class DateString extends HTMLElement {
  constructor() {
    super()
    return
  }

  // 返回需要监听的属性,当属性值改变的时候会调用 attributeChangedCallback 这个方法
  static get observedAttributes () {
    return ["ln"]
  }

  attributeChangedCallback (name, oldValue, newValue) {
    this.updateRendering (newValue)
  }

  // 元素插入到文档中时调用
  connectedCallback() {
    const ln = this.getAttribute("ln")
    this.updateRendering(ln)
  }

  // 元素从文档中移除时调用
  disconnectedCallback () {
    window.clearInterval(this.interval)
  }

  updateRendering (ln = "zh") {
    // 一个比较好的实践就是在渲染时,检查元素的 ownerDocument.defaultView, 如果不存在则什么都不干
    if (!this.ownerDocument.defaultView) {
      return
    }
    if (this.interval) {
      window.clearInterval(this.interval)
    }
    this.interval = setInterval(() => {
      if (ln === "zh") {
        this.innerHTML = new Date().toLocaleString()
      } else {
        this.innerHTML = new Date().toString()
      }
    }, 1000)
  }
}

然后调用 customElements.define() 注册这个自定义元素,设置属性并插入到 body 中。

    customElements.define("date-string", DateString)
    const dateStr = document.createElement("date-string")
    dateStr.setAttribute("ln", "zh")
    document.body.appendChild(dateStr)

也可以用直接调用构造函数创建元素

  const dateStr = new DateString()
  dateStr.setAttribute("ln", "zh")
  document.body.appendChild(dateStr)

自定义元素可以使用符合规范的任意属性名,下面说的派生内置元素类型要自定义属性,则要用 data-*

上面代码那样设置属性很繁琐,我们可以做一个属性映射,以期望 dateStr.ln = "zh" 这样赋值

class DateString extends HTMLElement {
  ...

  get ln () {
    return this.getAttribute("ln")
  }

  set ln (value) {
    this.setAttribute("ln", value)
  }
}
元素升级

除了像上面那样用 JavaScript 代码创建元素并添加到 body 下面,也可以直接在 HTML 写自定义元素




  
  
  
  Document


  
  

上面的代码依然正常工作。首先浏览器正常解析文档,遇到 标签时,把它当做一个普通的行内元素对待,实际上是 HTMElement 类型(如果标签的名称中没有中划线,,那么则是 HTMLUnknownElement 类型实例)。当 派生内置元素类型

除了从 HTMLElement 派生自定义元素,我们还可以从 HTMLButtonElement, HTMLDivElement 等内置元素类型派生自定义元素。这么做的好处是,可以保留内置元素的语义化功能。比如,HTMLButtonElement 有 active 状态,通过按 tab 键可以使 button 元素获得焦点,然后按回车键相当于点击 button 元素。现在我们从 HTMLButtonElement 派生一个自定义的按钮,并在点击的时候改变背景颜色。




  
  
  
  Document


  
  

这个按钮在行为上与内置的 button 一样, 可以获取焦点,提交表单,也有禁用属性等。

派生内置元素与自定义元素略微不同,调用 customElements.define 时要传入第三个参数表明是从那个元素派生,这里使用的名称是 "button" 即标签名,因为浏览器是靠识别标签名来提供语义和默认行为,基于这一点,使用的时候也是用的原本的标签名 button,然后再给一个 is 属性指定自定义元素的名称。

通过 document.createElement 创建元素时也有不同

const coloredButton = document.createElement("button", {
  is: "colored-button"
})

也可以直接调用构造函数创建

const coloredButton = new ColoredButton

console.log(coloredButton.localName) // => "button"
console.log(coloredButton.getAttribute(is)) // => "colored-button"

注:直到 chrome 61 版本,扩展内置元素依然在开发中。参见链接

构造函数的一些限制

自定义元素的构造函数必须遵循如下限制

构造函数中不能调用 document.write() 和 document.open()

不能访问元素的属性和子元素,因为在元素未升级的情况下(元素还未插入文档中),不存在属性和子元素

初始化工作要尽量推迟到 connectedCallback 中,尤其是涉及获取资源或渲染的工作。但是 connectedCallback 可能会调用多次(每次插入到文档中时都会调用),一次性的初始化工作需要自己设置防护措施。

命名限制

自定义元素的命名限制如下

必须以小写字母开头

必须有至少一个中划线

允许小写字母,中划线,下划线,点号,数字

允许部分 Unicode 字符,所以 这样也是可以的.

不允许下面这些名称

annotation-xml

color-profile

font-face

font-face-src

font-face-uri

font-face-format

font-face-name

missing-glyph

如果名称出现不允许的字符, customElements.define 会报错。

生命周期函数

自定义元素可以定义特殊生命周期钩子,以便在其存续的特定时间内运行代码。

constructor 创建或升级元素的一个实例。用于初始化状态、设置事件侦听器。

connectedCallback 元素每次插入到 DOM 时都会调用。可用于获取资源或渲染。

disconnectedCallback 元素每次从 DOM 中移除时都会调用。用于运行清理代码。

attributeChangedCallback 属性添加、移除、更新或替换。仅对 observedAttributes 中返回的属性有效。

adoptedCallback 自定义元素被移入新的 document 时调用。

响应回调是同步的。如果有人对您的元素调用 el.setAttribute(...),浏览器将立即调用 attributeChangedCallback()。 同理,从 DOM 中移除元素(例如用户调用 el.remove())后,您会立即收到 disconnectedCallback()。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/88907.html

相关文章

  • WebComponent魔法堂:深究Custom Element 之 标准构建

    摘要:明确各阶段适合的操作用于初始化元素的状态和设置事件监听,或者创建。事件类型转换通过捕获事件,然后通过发起事件来对事件类型进行转换,从而触发更符合元素特征的事件类型。 前言  通过《WebComponent魔法堂:深究Custom Element 之 面向痛点编程》,我们明白到其实Custom Element并不是什么新东西,我们甚至可以在IE5.5上定义自己的alert元素。但这种简单...

    philadelphia 评论0 收藏0
  • 定义元素探秘及构建可复用组件最佳实践

    摘要:若自定义元素标签名称不可用则摒弃。总之,自定义元素让开发者的代码更易理解和维护,并分割为小型,可复用及可封装的模块。被称为自定义元素接口,虽然现在仍然可用,但是已经被弃用并被认为是糟糕的实现。 原文请查阅这里,略有删减,本文采用知识共享署名 4.0 国际许可协议共享,BY Troland。 这是 JavaScript 工作原理第十九章。 概述 在 前述文章中,我们介绍了 Shadow ...

    CoorChice 评论0 收藏0
  • Angular Elements 及其运作原理

    摘要:以下是关于中一些模块的概要以及它们与这篇文章的关联性这个模块实现了我们在这篇文章中讨论的关于的几个回调函数,同时它还会初始化一个策略类,这个类会作为连接和的桥梁。 现在,Angular Elements 这个项目已经在社区引起一定程度的讨论。这是显而易见的,因为 Angular Elements 提供了很多开箱即用的、十分强大的功能: 通过使用原生的 HTML 语法来使用 Angul...

    qingshanli1988 评论0 收藏0
  • 使用 custom element 创建定义元素

    摘要:通过创建元素时也有不同也可以直接调用构造函数创建注直到版本,扩展内置元素依然在开发中。自定义元素被移入新的时调用。 很早我们就可以在 HTML 文档中写 这样的自定义名称标签。但是浏览器对于不认识的标签一律当成一个普通的行内元素处理,没有相关语义。虽然我们能用 JavaScript 代码给它添加一些功能,但是并没有生命周期相关的函数供我们做一些初始化和销毁的处理。 通过浏览器提供...

    Allen 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<