代码之家  ›  专栏  ›  技术社区  ›  Sora2455

无法设置自定义内置元素的文本内容,超时除外

  •  0
  • Sora2455  · 技术社区  · 2 年前

    我正在制作一个定制元素,自动定位其视觉文本表示:

    class LocalDate extends HTMLTimeElement {
      // Specify observed attributes so that
      // attributeChangedCallback will work
      static get observedAttributes() {
        return ["datetime"];
      }
    
      constructor() {
        // Always call super first in constructor
        const self = super();
    
        this.formatter = new Intl.DateTimeFormat(navigator.languages, {
          year: "numeric",
          month: "short",
          day: "numeric"
        });
    
        return self;
      }
    
      attributeChangedCallback(name, oldValue, newValue) {
        if (name === "datetime") {
          this.textContent = "";
          const dateMiliseconds = Date.parse(newValue);
          if (!Number.isNaN(dateMiliseconds)) {
            const dateString = this.formatter.format(new Date(dateMiliseconds));
            this.textContent = dateString;
          }
        }
      }
    }
    
    customElements.define('local-date', LocalDate, {
      extends: "time"
    });
    <time is="local-date" datetime="2022-01-13T07:13:00+10:00">13 Jan 2022 - Still here</time>

    kicker指的是脚本标签的运行时间——如果它是在解析主体之后运行的,那么它会按预期工作。否则,该元素将显示日期字符串,而不是显示为日期 除了 元素中已经存在的文本。

    JSFIDLE和StackOverflow都将脚本标记放在正文的底部,因此只能通过DataUrl看到错误:

    我在Firefox和Chrome中都复制了这一点——你知道这是怎么回事吗?

    0 回复  |  直到 2 年前
        1
  •  1
  •   Danny '365CSI' Engelman daniel p    2 年前

    你的问题发生了,
    因为两者都有 attributeChangedCallback connectedCallback 向地面开火 开场白
    (按这个顺序!)

    所以

    • 当自定义元素 定义 之前 在DOM中使用,
    • 这个 属性更改回调 向地面开火 开放 标签
    • 添加您的 .textContent
    • 之后 轻盈 从您的自定义元素是 解析
    • 默认情况下 补充 对现有内容的修改

    这就是为什么你会看到 lightDOM #2 在下面的例子中

    <style>
      time {
        display: block
      }
    </style>
    
    <time id=BEFORE is="local-date" datetime="2022-01-13T07:13:00+10:00"> lightDOM #1
      <script>console.log("time element BEFORE parsed")</script>
    </time>
    
    <script>
      customElements.define('local-date', class extends HTMLTimeElement {
        static get observedAttributes() {
          return ["datetime"];
        }
        attributeChangedCallback(name, oldValue, newValue) {
          console.warn("attributeChangedCallback", this.id, this.isConnected);
          this.textContent = (new Intl.DateTimeFormat(navigator.languages, {
            year: "numeric",
            month: "short",
            day: "numeric"
          })).format(new Date(Date.parse(newValue)));
        }
      }, {
        extends: "time"
      });
      console.warn("Custom Element: local-date defined");
    </script>
    
    <time id=AFTER is="local-date" datetime="2022-01-13T07:13:00+10:00"> lightDOM #2
      <script>console.log("time element AFTER parsed")</script>
    </time>

    不要在文件中进行初始化 属性更改回调

    <style>
      local-date {
        display: block
      }
    </style>
    
    <local-date id=BEFORE datetime="2022-01-13T07:13:00+10:00"> lightDOM #1
      <script>console.log("time element BEFORE parsed")</script>
    </local-date>
    
    <script>
      customElements.define('local-date', class extends HTMLElement {
        static get observedAttributes() {
          return ["datetime"];
        }
        attributeChangedCallback(name, oldValue, newValue) {
          console.warn("attributeChangedCallback", this.id, this.isConnected);
          if (oldValue) this.renderTime(newValue);
        }
        connectedCallback(){
          console.warn("connectedCallback", this.id);
          setTimeout(()=>this.renderTime());
        }
        renderTime(dt=this.getAttribute("datetime")){
          console.warn("renderTime", this.id);
          this.textContent = (new Intl.DateTimeFormat(navigator.languages, {
            year: "numeric",
            month: "short",
            day: "numeric"
          })).format(new Date(Date.parse(dt)));
        }
      });
      console.warn("Custom Element: local-date defined");
    </script>
    
    <local-date id=AFTER datetime="2022-01-13T07:13:00+10:00"> lightDOM #2
      <script>console.log("time element AFTER parsed")</script>
    </local-date>