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

如何在Slate JS中给指定关键词上色 输入关键词文本重复如何解决

问题原因与修复方案
  • 核心导致输入文本重复的原因:decorate 函数没有被稳定化,每次 CodeEditor 组件重渲染都会生成全新的 decorate 实例,触发 Editable 高频重绘,进而出现文本重复、光标错位的问题。
  • 高亮不生效的原因:Leaf 组件中自定义 style 写在了 {...attributes} 之前,Slate 内置的 attributes 会覆盖你定义的样式属性,导致自定义颜色不生效。
  • 额外冗余逻辑问题:log 函数直接包装返回 children 会额外触发不必要的渲染开销,getLength 函数的递归逻辑完全冗余,当前分词逻辑下直接取字符串长度即可。

修复后的完整代码

import { Editable, Slate, withReact } from "slate-react";
import React, { useMemo, useState, useCallback } from "react";
import { Text, createEditor } from "slate";
import { withHistory } from "slate-history";

const log = (x) => {
  console.log(x);
};
const tokenize = (text) =>
  text
    .split(/(\s+)/)
    .map((x) => (x === "hello" ? { content: x, type: "keyword" } : x));

const Leaf = ({ attributes, children, leaf }) => {
  log(leaf);
  log(children);
  return (
    <span
      {...attributes}
      style={{ color: leaf.keyword ? "green" : "black" }}
    >
      {children}
    </span>
  );
};

const CodeEditor = () => {
  const [value, setValue] = useState([
    {
      type: "paragraph",
      children: [
        {
          text: "",
        },
      ],
    },
  ]);
  const editor = useMemo(() => withHistory(withReact(createEditor())), []);

  const handleChange = useCallback((newValue) => {
    setValue(newValue);
  }, []);

  const decorate = useCallback(([node, path]) => {
    if (!Text.isText(node)) {
      return [];
    }
    const ranges = [];
    const tokens = tokenize(node.text);
    let start = 0;
    for (const token of tokens) {
      const end = start + (typeof token === 'string' ? token.length : token.content.length);
      if (typeof token !== "string") {
        ranges.push({
          [token.type]: true,
          anchor: { path, offset: start },
          focus: { path, offset: end },
        });
      }
      start = end;
    }
    return ranges;
  }, []);

  return (
    <Slate editor={editor} value={value} onChange={handleChange}>
      <Editable
        decorate={decorate}
        renderLeaf={(props) => <Leaf {...props} />}
        placeholder="Write some code..."
      />
    </Slate>
  );
};

export default CodeEditor;

可选优化

当前分词逻辑仅能匹配被空格完全包裹的hello,如果需要匹配行首、行尾、标点旁的独立单词,可以将分词逻辑调整为正则全局匹配单词边界/\b(hello)\b/g,适配更多场景。

内容的提问来源于stack exchange,提问作者Uri

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 07:39:04