通过 createElement 创建 WebComponent

我在使用 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 = ''

})

有任何想法吗?谢谢。


三国纷争
浏览 135回答 1
1回答

慕田峪9158850

constructor永远无法创建在中设置 DOM 内容的自定义元素document.createElement()您将看到许多示例(包括我的示例),其中 DOM 内容是在构造函数中设置的。这些元素永远无法创建document.createElement说明(HTML DOM API):当您使用时:&nbsp; <todo-card content=FOO></todo-card>该元素(从 HTMLElement 扩展)具有所有 HTML 接口(它在 HTML DOM 中),您可以在构造函数中设置 innerHTML但是,当你这样做时:&nbsp; document.createElement("todo-card");构造函数在没有 HTML 接口的情况下运行(元素可能与 DOM 无关),因此在构造函数中设置 innerHTML会产生错误:未捕获的 DOMException:无法构造“CustomElement”:结果不得有子项来自https://html.spec.whatwg.org/multipage/custom-elements.html#custom-element-conformance:该元素不得获得任何属性或子元素,因为这违反了使用 createElement 或 createElementNS 方法的消费者的期望。一般来说,工作应该尽可能推迟到 connectedCallbackshadowDOM 是一个 DOM使用shadowDOM时,您可以在构造函数中设置shadowDOM内容:&nbsp; constructor(){&nbsp; &nbsp; super().attachShadow({mode:"open"})&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.innerHTML = `...`;&nbsp; }正确的代码(没有 shadowDOM):使用connectedCallback:<todo-card content=FOO></todo-card><script>&nbsp; window.customElements.define(&nbsp; &nbsp; "todo-card",&nbsp; &nbsp; class extends HTMLElement {&nbsp; &nbsp; &nbsp; constructor() {&nbsp; &nbsp; &nbsp; &nbsp; super();&nbsp; &nbsp; &nbsp; &nbsp; //this.innerHTML = this.getAttribute("content");&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; connectedCallback() {&nbsp; &nbsp; &nbsp; &nbsp; this.innerHTML = this.getAttribute("content");&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; );&nbsp; try {&nbsp; &nbsp; const todo = document.createElement("todo-card");&nbsp; &nbsp; todo.setAttribute("content", "BAR");&nbsp; &nbsp; document.body.appendChild(todo);&nbsp; } catch (e) {&nbsp; &nbsp; console.error(e);&nbsp; }</script>您还有另一个小问题:content&nbsp;是默认属性,FireFox 不会停止警告您:或者不使用 createElement&nbsp; const todo = document.createElement("todo-card");&nbsp; todo.setAttribute("content", "BAR");&nbsp; document.body.appendChild(todo);可以写成:&nbsp; const html = `<todo-card content="BAR"></todo-card`;&nbsp; document.body.insertAdjacentHTML("beforeend" , html);&nbsp;可以connectedCallback运行多次!当你四处移动 DOM 节点时:<div id=DO_Learn>&nbsp; <b>DO Learn: </b><todo-card todo="Custom Elements API"></todo-card></div><div id="DONT_Learn">&nbsp; <b>DON'T Learn!!! </b><todo-card todo="React"></todo-card></div><script>&nbsp; window.customElements.define(&nbsp; &nbsp; "todo-card",&nbsp; &nbsp; class extends HTMLElement {&nbsp; &nbsp; &nbsp; connectedCallback() {&nbsp; &nbsp; &nbsp; &nbsp; let txt = this.getAttribute("todo");&nbsp; &nbsp; &nbsp; &nbsp; this.append(txt);// and appended again on DOM moves&nbsp; &nbsp; &nbsp; &nbsp; console.log("qqmp connectedCallback\t", this.parentNode.id, this.innerHTML);&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; disconnectedCallback() {&nbsp; &nbsp; &nbsp; &nbsp; console.log("disconnectedCallback\t", this.parentNode.id , this.innerHTML);&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; );&nbsp; const LIT = document.createElement("todo-card");&nbsp; LIT.setAttribute("todo", "Lit");&nbsp; DO_Learn.append(LIT);&nbsp; DONT_Learn.append(LIT);</script>LIT 的 connectedCallback 运行移动 LIT 时disconnectedCallback 运行(注意父级!元素已经在新位置)LIT 的 connectedCallback 再次运行,再次"Learn Lit"&nbsp;追加这取决于你的程序员你的组件/应用程序必须如何处理这个Web 组件库像 Lit、HyperHTML 和 Hybrids 这样的库实现了额外的回调来帮助解决所有这些问题。我建议先学习自定义元素 API,否则你学习的是工具而不是技术。有工具的傻瓜,仍然是傻瓜
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript