JavaScript实例化自定义内置元素失效问题排查
问题分析与修复
你开发的递归自定义内置元素,HTML初始化的实例能正常工作,但JavaScript生成的子元素无法继承自定义特性,核心问题出在自定义内置元素的创建方式,和页面生命周期关联不大,具体原因及修复方案如下:
核心问题点
自定义内置元素创建错误:
你通过document.createElement('ul')后再设置is属性的方式,无法将普通<ul>升级为test-list自定义元素实例,它仍然是原生HTMLUListElement,自然没有你定义的datasetter和render方法。递归数据赋值逻辑错误:
你在render方法里给子列表赋值newlist.data = data;,这里的data是全局变量,而非当前元素的element.data,会导致所有子列表重复渲染全局数据,逻辑完全错误。
修复后的代码
HTML代码(无需修改)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <ul is="test-list" id="testList"> </ul> <script type="module" src="/js/test-list-element.js"></script> <script> let data = [ { name: 'a', data: [{ name: 'a', data: [] }, { name: 'b', data: [] }, { name: 'c', data: [] }, { name: 'd', data: [] }] }, { name: 'b', data: [{ name: 'a', data: [] }, { name: 'b', data: [] }, { name: 'c', data: [] }, { name: 'd', data: [] }] }, { name: 'c', data: [{ name: 'a', data: [] }, { name: 'b', data: [] }, { name: 'c', data: [] }, { name: 'd', data: [] }] }, { name: 'd', data: [{ name: 'a', data: [] }, { name: 'b', data: [] }, { name: 'c', data: [] }, { name: 'd', data: [] }] }, ]; window.onload = (event) => { let listElement = document.getElementById("testList"); listElement.data = data; } </script> </body> </html>
修复后的test-list-element.js
class testList extends HTMLUListElement { constructor() { super(); this.render = this.render.bind(this); } #data = null; set data(value) { this.#data = value; this.render(); } render(){ if(!this.#data) return; this.#data.forEach(element => { let newItem = document.createElement('li'); newItem.innerText = element.name; this.appendChild(newItem); // 增加子数组长度判断,避免空数组创建空列表 if(element.data && element.data.length > 0) { // 正确创建自定义内置元素的方式 let newlist = document.createElement('ul', { is: 'test-list' }); // 赋值当前元素的子数据,而非全局data newlist.data = element.data; newItem.appendChild(newlist); } }); } } customElements.define('test-list', testList, { extends: 'ul' });
补充说明
- 继承原生HTML元素的自定义内置元素,必须通过
document.createElement(tagName, { is: 'custom-tag-name' })的方式创建,才能得到自定义元素实例。 - 递归渲染时要严格使用当前节点的子数据,避免引用全局变量导致逻辑错误。
内容的提问来源于stack exchange,提问作者kevin
相关产品推荐
相关产品推荐

