You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义元素动态生成异常:需在创建阶段设置属性

问题分析

你遇到的核心问题是:自定义元素的constructor在document.createElement调用时就会立即执行,此时你还没调用setAttribute设置src和href属性,所以this.getAttribute("src")和this.getAttribute("href")返回的都是null,导致Shadow DOM里的图片和链接无法正确渲染,最终只显示CSS定义的空方框。

窗口 resize 后异常,是因为重新执行createDivItems时,重复了同样的错误流程——先创建元素(触发constructor,此时属性未设置),再设置属性,但constructor已经执行过,不会重新触发渲染。

解决方案

1. 修改自定义元素代码,监听属性变化

自定义元素提供了attributeChangedCallback生命周期钩子,用来监听属性变化,当属性更新时自动重新渲染内容。同时需要通过observedAttributes指定要监听的属性:

class Item extends HTMLElement {
    constructor() {
        super();
        this.attachShadow({ mode: 'open'});
        // 初始化渲染(此时属性可能未设置,显示默认值)
        this.render();
    }

    // 指定需要监听的属性列表
    static get observedAttributes() {
        return ['src', 'href'];
    }

    // 属性变化时触发,重新渲染内容
    attributeChangedCallback(name, oldValue, newValue) {
        if (oldValue !== newValue) {
            this.render();
        }
    }

    // 提取渲染逻辑为独立方法,方便复用
    render() {
        const src = this.getAttribute("src");
        const link = this.getAttribute("href");
        const text = this.textContent.trim();
        
        this.shadowRoot.innerHTML = `
        <style>/* Styles excluded */</style>
        <div>
            <a href='${link || '#'}'>
                <div class="bg">
                    <img src="${src || ''}" alt="${text || 'Item'}">
                </div>
                <p>${text || 'not used.'}</p>
            </a>
        </div>
        `;
    }
}

customElements.define('div-item', Item);

2. 修正动态创建元素的代码

document.createElement的第二个参数不是用来传递属性的(它仅用于自定义元素的is选项等场景),直接删除无效的第二个参数,保留setAttribute逻辑即可:

function createDivItems() {
  var rows = document.getElementsByClassName("row");

  for (var j = 0; j < rows.length; j++) {
    var row = rows[j];
    row.innerHTML = '';

    for (var i = 0; i < (window.innerWidth - 60); i += 120) {
      // 正确创建自定义元素,无需在第二个参数传属性
      var elem = document.createElement("div-item");

      // 设置属性,此时会触发attributeChangedCallback重新渲染
      elem.setAttribute("src", '<?php echo "assets/not found.png"; ?>');
      elem.setAttribute("href", '<?php echo "/newPage.php"; ?>');
      elem.textContent = 'not used.';

      row.appendChild(elem);
    }
  }
}

额外说明:延迟显示正常的原因

延迟执行时,相当于先创建元素并添加到DOM,之后再设置属性,此时attributeChangedCallback会被触发,触发重新渲染,所以内容能正常显示。但窗口resize时重新执行createDivItems,又回到了先创建元素(constructor执行时属性为空)再设置属性的流程,没有attributeChangedCallback的话,constructor不会再次执行,因此仍然显示空方框。

内容的提问来源于stack exchange,提问作者Slothscript

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 22:02:17