React中textarea的HTML标签自动补全功能开发求助
React Textarea HTML标签自动补全问题修复
原代码存在的核心问题
- 错误依赖状态
currentText获取光标位置:React状态更新是异步的,currentText无法实时匹配textarea的当前输入值,应该直接通过event.target获取实时值与光标位置 - 标签提取逻辑失效:通过空格分割字符串的方式,无法正确识别带属性的HTML标签(如
<div class="container">),会错误提取属性部分而非标签名 - 无标准HTML标签校验:所有含
<的字符串都会触发补全,无法区分合法HTML标签与自定义标签 - 光标位置未优化:补全闭合标签后光标直接跳到文本末尾,打断输入流程
- 未排除自闭合标签:
<img>、<br>这类自闭合标签不需要生成闭合标签
修复后的完整代码
import React, { useState } from "react"; // 定义需要补全的标准HTML标签(排除自闭合标签) const VALID_HTML_TAGS = new Set([ "html", "head", "title", "body", "div", "p", "h1", "h2", "h3", "h4", "h5", "h6", "span", "a", "ul", "ol", "li", "table", "tr", "td", "th", "form", "textarea", "select", "option", "button", "header", "footer", "nav", "section", "article" ]); // 定义自闭合HTML标签,不需要补全 const SELF_CLOSING_TAGS = new Set([ "img", "br", "hr", "input", "meta", "link", "area", "base", "col", "command", "embed", "keygen", "param", "source", "track", "wbr" ]); const Text = () => { const [currentText, setCurrentText] = useState(""); const addClosingTag = (event) => { // 仅在输入>时处理 if (event.key !== ">") return; const target = event.target; const currentValue = target.value; const selectionStart = target.selectionStart; // 获取光标前的文本,找到最后一个<的位置 const textBeforeCursor = currentValue.slice(0, selectionStart); const lastOpenTagIndex = textBeforeCursor.lastIndexOf("<"); if (lastOpenTagIndex === -1) return; // 提取标签名:从<之后到第一个空格或>之前的部分 const tagContent = textBeforeCursor.slice(lastOpenTagIndex + 1); const tagNameMatch = tagContent.match(/^[a-z]+/i); if (!tagNameMatch) return; const tagName = tagNameMatch[0].toLowerCase(); // 校验:必须是有效HTML标签且不是自闭合标签 if (!VALID_HTML_TAGS.has(tagName) || SELF_CLOSING_TAGS.has(tagName)) return; // 构造补全后的文本:原文本 + 闭合标签,同时保留光标后的内容 const textAfterCursor = currentValue.slice(selectionStart); const newText = `${currentValue.slice(0, selectionStart + 1)}</${tagName}>${textAfterCursor}`; setCurrentText(newText); // 调整光标位置到开标签和闭标签之间 setTimeout(() => { target.selectionStart = target.selectionEnd = selectionStart + 1; }, 0); }; return ( <div> <textarea value={currentText} onChange={(event) => setCurrentText(event.target.value)} onKeyDown={(event) => addClosingTag(event)} rows={10} cols={80} /> </div> ); }; export default Text;
关键修复点说明
- 标签校验:通过
VALID_HTML_TAGS和SELF_CLOSING_TAGS两个集合,精准控制需要补全的标签范围,自定义标签(如<laptop>)不会触发补全 - 正确提取标签名:使用正则表达式
/^[a-z]+/i从<之后提取标签名,支持带属性的标签(如<div class="box">) - 实时值获取:直接通过
event.target获取textarea的当前值和光标位置,避免异步状态更新带来的偏差 - 光标位置优化:补全标签后,通过
setTimeout调整光标到开标签与闭标签之间,保持输入连贯性 - 自闭合标签排除:提前过滤不需要补全的自闭合标签,避免无效操作
内容的提问来源于stack exchange,提问作者eagle_bear
相关产品推荐
相关产品推荐

