为了账号安全,请及时绑定邮箱和手机立即绑定

通过 createElement 创建 WebComponent

通过 createElement 创建 WebComponent

三国纷争 2022-12-02 10:36:53
我在使用 createElement 创建 Web 组件时遇到问题。我收到此错误:未捕获的 DOMException:无法构造“CustomElement”:结果在 appendTodo 中不能有子项class TodoCard extends HTMLElement {    constructor() {        super()        this.innerHTML = `            <li>                <div class="card">                    <span class="card-content">${this.getAttribute('content')}</span>                    <i class="fa fa-circle-o" aria-hidden="true"></i>                    <i class="fa fa-star-o" aria-hidden="true"></i>                </div>            </li>        `    }}window.customElements.define('todo-card', TodoCard)const todoList = document.getElementById('todo-list')const todoForm = document.getElementById('todo-form')const todoInput = document.getElementById('todo-input')function appendTodo(content) {    const todo = document.createElement('todo-card')    todo.setAttribute('content', content)    todoList.appendChild(todo)}todoForm.addEventListener('submit', e => {    e.preventDefault()    appendTodo(todoInput.value)    todoInput.value = ''})有任何想法吗?谢谢。
查看完整描述

1 回答

?
慕田峪9158850

TA贡献1794条经验 获得超7个赞

constructor

永远无法创建在中设置 DOM 内容的自定义元素document.createElement()


您将看到许多示例(包括我的示例),其中 DOM 内容是在构造函数中设置的。

这些元素永远无法创建document.createElement


说明(HTML DOM API):

当您使用时:


  <todo-card content=FOO></todo-card>

该元素(从 HTMLElement 扩展)具有所有 HTML 接口(它在 HTML DOM 中),

您可以在构造函数中设置 innerHTML


但是,当你这样做时:


  document.createElement("todo-card");

构造函数在没有 HTML 接口的情况下运行(元素可能与 DOM 无关),因此在构造函数

中设置 innerHTML会产生错误:


未捕获的 DOMException:无法构造“CustomElement”:结果不得有子项


来自https://html.spec.whatwg.org/multipage/custom-elements.html#custom-element-conformance:


该元素不得获得任何属性或子元素,因为这违反了使用 createElement 或 createElementNS 方法的消费者的期望。一般来说,工作应该尽可能推迟到 connectedCallback


shadowDOM 是一个 DOM

使用shadowDOM时,您可以在构造函数中设置shadowDOM内容:


  constructor(){

    super().attachShadow({mode:"open"})

           .innerHTML = `...`;

  }

正确的代码(没有 shadowDOM):使用connectedCallback:

<todo-card content=FOO></todo-card>


<script>

  window.customElements.define(

    "todo-card",

    class extends HTMLElement {

      constructor() {

        super();

        //this.innerHTML = this.getAttribute("content");

      }

      connectedCallback() {

        this.innerHTML = this.getAttribute("content");

      }

    }

  );


  try {

    const todo = document.createElement("todo-card");

    todo.setAttribute("content", "BAR");

    document.body.appendChild(todo);

  } catch (e) {

    console.error(e);

  }

</script>

您还有另一个小问题:content 默认属性,FireFox 不会停止警告您:

//img1.sycdn.imooc.com//638964ee0001f6fa05700020.jpg

或者不使用 createElement

  const todo = document.createElement("todo-card");

  todo.setAttribute("content", "BAR");

  document.body.appendChild(todo);

可以写成:


  const html = `<todo-card content="BAR"></todo-card`;

  document.body.insertAdjacentHTML("beforeend" , html); 

可以connectedCallback运行多次!

当你四处移动 DOM 节点时:


<div id=DO_Learn>

  <b>DO Learn: </b><todo-card todo="Custom Elements API"></todo-card>

</div>

<div id="DONT_Learn">

  <b>DON'T Learn!!! </b><todo-card todo="React"></todo-card>

</div>

<script>

  window.customElements.define(

    "todo-card",

    class extends HTMLElement {

      connectedCallback() {

        let txt = this.getAttribute("todo");

        this.append(txt);// and appended again on DOM moves

        console.log("qqmp connectedCallback\t", this.parentNode.id, this.innerHTML);

      }

      disconnectedCallback() {

        console.log("disconnectedCallback\t", this.parentNode.id , this.innerHTML);

      }

    }

  );

  const LIT = document.createElement("todo-card");

  LIT.setAttribute("todo", "Lit");

  DO_Learn.append(LIT);

  DONT_Learn.append(LIT);

</script>

  • LIT 的 connectedCallback 运行

  • 移动 LIT 时

  • disconnectedCallback 运行(注意父级!元素已经在新位置)

  • LIT 的 connectedCallback 再次运行,再次"Learn Lit" 追加

这取决于你的程序员你的组件/应用程序必须如何处理这个

Web 组件库

像 Lit、HyperHTML 和 Hybrids 这样的库实现了额外的回调来帮助解决所有这些问题。

我建议先学习自定义元素 API,否则你学习的是工具而不是技术。

有工具的傻瓜,仍然是傻瓜


查看完整回答
反对 回复 2022-12-02
  • 1 回答
  • 0 关注
  • 134 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信