如何在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
相关产品推荐
相关产品推荐

