StencilJS:在JSX/TSX中渲染原生节点遇undefined问题求助
问题分析与解决方案
核心错误点
- 事件绑定拼写错误:原生
slotchange事件在Stencil JSX中需用驼峰式onSlotChange(大写C),你写的onSlotchange无法触发事件处理函数,导致rows始终为空。 - 重复渲染冲突:同时保留
<slot>标签和手动渲染rows,会让浏览器默认渲染插槽内容,同时你手动渲染DOM元素实例,引发逻辑冲突。 - 数组更新逻辑错误:每次
slotchange都追加元素到rows,会导致多次触发时数组重复添加相同元素。
修正后的代码
import { Component, Element, State, Host } from '@stencil/core'; @Component({ tag: 'custom-table-body', shadow: true }) export class CustomTableBody { @Element() host: HTMLElement; @State() private rows: Element[] = []; private onSlotChange(event: Event) { const slot = event.target as HTMLSlotElement; // 获取所有分配到插槽的元素,flatten: true可展开嵌套元素(按需使用) const assignedElements = slot.assignedElements({ flatten: true }); // 过滤仅保留custom-table-row元素(可选,确保行类型正确) this.rows = assignedElements.filter(el => el.tagName.toLowerCase() === 'custom-table-row'); } render() { return ( <Host role="rowgroup"> {/* 隐藏原始插槽,仅用于捕获内容变化 */} <slot onSlotChange={(e) => this.onSlotChange(e)} style={{ display: 'none' }} /> {/* 手动渲染行元素,添加唯一key确保正确重渲染 */} {this.rows.map((row, index) => ( <span key={index}>{row}</span> {/* 若无需包裹元素,可改用Fragment:<>{row}</> */} ))} </Host> ); } }
关键说明
- 隐藏原始插槽:避免浏览器默认渲染插槽内容,仅用它监听内容变化。
- 正确获取插槽元素:
assignedElements({ flatten: true })确保拿到所有分配的元素,包括嵌套在其他容器中的行(如果有)。 - 唯一Key:给每个渲染的行元素添加唯一key,保证组件重渲染时的性能和正确性,优先使用行元素的唯一标识(如
id),临时场景可用索引替代。
内容的提问来源于stack exchange,提问作者Marco
相关产品推荐
相关产品推荐

