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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 07:50:18