Draft.js自定义Decorator无效果问题排查与解决求助
我尝试为Draft.js制作第一个Decorator,按照文档实现了LinkDecorator、Utils工具类,并在MyEditor中使用,但用户输入链接时,页面上只显示输入的链接文本,没有替换成指向Google的链接。即使修改了LinkDecorator.js中matchFunction里的Utils.regexMatch参数为Utils.regexMatch(regex,contentBlock,callback),问题依然存在。
现有代码实现
1. LinkDecorator.js
import React from 'react'; import Utils from './Utils'; const Link= (props) => { console.log(props); return ( <a href="http://google.com">GOOGLE</a> ); } const matchFunction = (contentBlock, callback, contentState) => { const regex=/(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9]\.[^\s]{2,})/ Utils.regexMatch(regex,contentBlock,callback); } export default { 'strategy': matchFunction, 'component': Link };
2. Utils.js
export default { 'regexMatch': (regex, contentBlock, callback)=>{ const text = contentBlock.getText(); let matchArr = regex.exec(text); let start; console.log("Block Content", text); while (matchArr !== null) { start = matchArr.index; callback(start, start + matchArr[0].length); matchArr = regex.exec(text); } }, }
3. MyEditor.js
import React, { Component } from 'react'; import { EditorState, CompositeDecorator } from 'draft-js'; import { Editor } from 'react-draft-wysiwyg'; import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css'; import Link from './LinkDecorator'; class MyEditor extends Component { constructor(props){ super(props); const compositeDecorator = new CompositeDecorator([Link]); this.state = { compositeDecorator, editorState: EditorState.createEmpty(compositeDecorator), }; } onEditorStateChange: Function = (editorState) => { this.setState({editorState,}); }; render() { const { editorState } = this.state; return ( <Editor editorState={editorState} wrapperClassName="demo-wrapper" editorClassName="demo-editor" onEditorStateChange={this.onEditorStateChange} /> ); } } export default MyEditor;
问题原因分析
1. 正则表达式缺少全局匹配标志
你的正则表达式没有添加g(全局匹配)标志,这会导致regex.exec(text)每次调用都从字符串开头开始匹配,永远返回第一个匹配结果,直接陷入无限循环——既无法遍历文本中所有链接,也不会正常触发Decorator的渲染逻辑。
2. 匹配循环逻辑失效
由于正则没有全局标志,regex.exec(text)不会自动推进匹配位置,循环无法终止,Decorator的strategy函数根本无法完成执行,自然不会调用callback来标记需要装饰的文本范围。
修复步骤
步骤1:给正则添加全局匹配标志
修改LinkDecorator.js中的正则定义,加上g标志:
const regex = /(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9]\.[^\s]{2,})/g;
步骤2:验证匹配循环正常执行
添加g标志后,regex.exec(text)会自动更新lastIndex,每次调用都会从上次匹配的结束位置开始查找,循环可以正常遍历所有匹配项,正确触发callback标记装饰范围。
步骤3:优化Link组件(可选)
如果你想显示用户输入的原链接文本而不是固定的"GOOGLE",可以修改Link组件使用Draft.js传递的children参数(即匹配到的原文本):
const Link = (props) => { console.log(props); return <a href="http://google.com">{props.children}</a>; };
步骤4:确认Editor配置有效性
react-draft-wysiwyg的Editor组件会正确继承editorState中的CompositeDecorator,你当前的代码已经在初始化时传入了Decorator,后续onEditorStateChange更新状态时也会自动保留,无需额外配置。
修复后的完整LinkDecorator.js
import React from 'react'; import Utils from './Utils'; const Link = (props) => { console.log(props); // 可选择显示原链接文本或固定文本 return <a href="http://google.com">{props.children}</a>; }; const matchFunction = (contentBlock, callback, contentState) => { // 添加全局匹配标志g const regex = /(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9]\.[^\s]{2,})/g; Utils.regexMatch(regex, contentBlock, callback); }; export default { strategy: matchFunction, component: Link };
额外提示
如果还是没生效,可以打开浏览器控制台检查是否有报错(比如之前正则无g标志导致的栈溢出),同时确认Utils.js中的regexMatch参数传递正确(你修改后的参数是对的,strategy函数的第二个参数就是callback)。
内容的提问来源于stack exchange,提问作者Dimitrios Desyllas

