“具感知能力”的HTML模板组件指能通过attributeChangedCallback、connectedCallback和slotchange事件原生响应属性变化、挂载状态及插槽内容变动的自定义元素;需避免在constructor中提前克隆未就绪的template,应延迟至connectedCallback获取,并为slot显式监听slotchange以触发更新。

什么是“具感知能力”的 HTML 模板组件
不是指 AI 感知,而是指组件能响应属性变化、挂载状态、插槽内容变动,并做出对应 DOM 更新——即具备 attributeChangedCallback、connectedCallback、slotchange 事件监听能力。这类组件不靠框架驱动,纯靠浏览器原生机制“感知”环境变化。
用 <template> 声明结构,但别在 constructor 里直接 clone
常见错误是:在 constructor 中就调用 document.getElementById('tpl').content.cloneNode(true) 并塞进 shadowRoot。此时模板可能还没被解析(尤其在 defer 脚本或动态插入场景下),getElementById 返回 null,直接报错。
- 正确做法:把模板获取逻辑移到
connectedCallback或封装成懒加载函数,首次挂载时检查是否存在,不存在则抛错或 warn -
<template>必须在 DOM ready 后才可用,推荐放在<head>底部或<body>顶部,避免竞态 - 若需多实例共享同一模板,用
static template = document.getElementById('xxx-tpl')?.content缓存,但要加空值防护
让组件“感知插槽内容变化”,必须监听 slotchange
仅靠 <slot> 标签本身不会触发更新;用户在组件内写 <my-card><p slot="desc">新描述</p></my-card>,DOM 已变,但组件内部无反应——除非你主动监听。
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- 在
connectedCallback中为每个<slot>添加slot.addEventListener('slotchange', ...) - 不要只监听一次:插槽内容可能多次替换,每次都要重新绑定或用事件委托
- 典型用途:根据是否有
slot="actions"决定是否显示操作栏,或统计slot="item"的子元素数量来渲染计数 badge - 注意:
slotchange不会告诉你内容变了什么,只通知“变了”,需手动 diffassignedNodes()
组合性依赖属性 + 插槽 + 生命周期协同,而非堆砌功能
所谓“可组合”,不是指组件功能越全越好,而是它能被其他组件自然包裹、透传属性、分发内容、响应嵌套生命周期。容易踩的坑是:在 attributeChangedCallback 里修改了属性,却没同步更新插槽内容;或监听了 slotchange,却没触发 _render() 重绘。
立即学习“前端免费学习笔记(深入)”;
- 属性变更和插槽变更应统一收敛到一个更新入口,比如
this._update(),避免状态不同步 - 如果组件支持
disabled属性,除了禁用按钮,还要在slotchange后检查子节点是否含交互元素并统一禁用 - 跨层级组合时(如
<form-layout><my-input></my-input></form-layout>),父组件无法直接读取子组件 shadowRoot,必须通过part属性或自定义事件通信
真正难的不是写多少代码,而是厘清哪件事该在哪一时刻发生:属性改了谁先响应、插槽内容替换后要不要重算布局、组件被移出 DOM 时要不要清理 slot 监听器——这些边界条件,才是“感知能力”的实际成本。


















