Svelte构建类Notion编辑器:contenteditable中span元素间空格问题
Svelte渲染带格式文本时,span元素间多余空格的解决方法
我用Svelte开发类Notion编辑器,按文本格式拆分生成的span元素之间总会出现多余的空格文本节点,导致排版不符合预期。生成的DOM结构如下:
<div contenteditable="true"> <p> <span contenteditable="true" id="a1" data-index="0">some text</span> <span contenteditable="true" id="a2" class="bold" data-index="0">some other text</span> </p> </div>
这些span之间的空白#textnode是Svelte渲染模板时默认插入的,试过各种CSS方案都没法消除,甚至把模板代码压缩成一行也没用。负责渲染的原模板代码是这样的:
{#each $fragments[$selectedFragment].children[childIndex].text as fragment, i} {#if fragment.tag == "span"} <span contenteditable="true" id={fragment.id} class="edit-row" data-index={i} class:bold={fragment?.formattingOptions?.bold} class:italic={fragment?.formattingOptions?.italic} >{fragment.text}</span> {/if} {/each}
下面是几种可行的解决方法:
方法1:用{@html}指令直接拼接HTML字符串
先在组件里把所有需要渲染的span拼接成完整的HTML字符串,再用Svelte的{@html}指令渲染,这样能完全避免框架自动插入空格。示例代码:
<script> import { derived } from 'svelte/store'; // 从store派生渲染所需的HTML字符串 const renderedSpans = derived( [$fragments, $selectedFragment], ([fragments, selectedFragment]) => { const targetTextFragments = fragments[selectedFragment]?.children[childIndex]?.text || []; return targetTextFragments .filter(fragment => fragment.tag === "span") .map((fragment, i) => ` <span contenteditable="true" id="${fragment.id}" class="edit-row ${fragment?.formattingOptions?.bold ? 'bold' : ''} ${fragment?.formattingOptions?.italic ? 'italic' : ''}" data-index="${i}" > ${fragment.text} </span> `).join(''); } ); </script> <!-- 直接渲染拼接好的HTML --> <p>{@html $renderedSpans}</p>
方法2:利用Svelte的空格抑制语法
Svelte支持在模板块标签的前后加-来抑制空格生成,修改原模板如下:
{#each $fragments[$selectedFragment].children[childIndex].text as fragment, i}- {#if fragment.tag == "span"}- <span contenteditable="true" id={fragment.id} class="edit-row" data-index={i} class:bold={fragment?.formattingOptions?.bold} class:italic={fragment?.formattingOptions?.italic} >{fragment.text}</span>- {/if}- {/each}
在{#each}、{#if}的末尾加-,闭合标签前也加-,Svelte就会移除这些位置的多余空格。
方法3:CSS临时兼容方案(慎用)
如果前两种方法暂时没法落地,可以给父元素p设置font-size: 0,再给span恢复正常字体大小,同时重置字符间距:
p.edit { font-size: 0; letter-spacing: 0; } p.edit span.edit-row { font-size: 16px; /* 根据你的需求调整 */ }
这个方法能视觉上消除空格,但DOM里的空白节点依然存在,可能影响其他inline元素的排版,只建议作为临时过渡方案。
内容的提问来源于stack exchange,提问作者Ray Remnant
相关产品推荐
相关产品推荐

