React TypeScript识别文本URL并转为可点击链接实现方法
React TypeScript 实现聊天消息URL自动转可点击链接
核心实现逻辑
不需要在useEffect中提前遍历修改聊天列表状态,直接在单条消息渲染阶段做文本拆分解析即可,避免不必要的状态更新和重渲染。
1. 修正URL匹配正则
原有正则缺少全局匹配标识g,无法识别单条消息内的多个URL,修正后的正则如下:
const urlRegex = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/g;
2. 编写文本解析工具函数
该函数会将原始消息字符串拆分为普通文本、URL两类片段,方便后续分别渲染:
// 可放在组件外部或公共工具文件中 const parseMessageContent = (content: string) => { const fragments: Array<{ type: 'text' | 'link'; value: string }> = []; // 无匹配直接返回原文本 if (!urlRegex.test(content)) { return [{ type: 'text', value: content }]; } // 重置正则匹配指针,避免连续匹配错位 urlRegex.lastIndex = 0; let lastEndIndex = 0; let matchResult: RegExpExecArray | null; while ((matchResult = urlRegex.exec(content)) !== null) { // 插入URL之前的普通文本 if (matchResult.index > lastEndIndex) { fragments.push({ type: 'text', value: content.slice(lastEndIndex, matchResult.index) }); } // 插入匹配到的URL片段 fragments.push({ type: 'link', value: matchResult[0] }); lastEndIndex = matchResult.index + matchResult[0].length; } // 插入末尾剩余的普通文本 if (lastEndIndex < content.length) { fragments.push({ type: 'text', value: content.slice(lastEndIndex) }); } return fragments; };
3. 修改消息渲染逻辑
替换原有直接输出message.message的代码,遍历解析后的片段分别渲染:
{chat.map((messageItem: IMessage, index) => { return ( <Paper key={index} style={{ backgroundColor: "#6096ba", padding: "5px", borderRadius: "30px", }} elevation={3} > <p style={{ maxWidth: "20ch", color: "white", wordBreak: "break-all" }}> {parseMessageContent(messageItem.message).map((fragment, fragIndex) => { if (fragment.type === 'link') { return ( <a key={fragIndex} href={fragment.value} target="_blank" rel="noopener noreferrer" style={{ color: '#e3f2fd', textDecoration: 'underline' }} > {fragment.value} </a> ) } return <span key={fragIndex}>{fragment.value}</span> })} </p> </Paper> ); })}
注意事项
- 给链接标签添加
rel="noopener noreferrer"是必要的安全配置,避免新打开的页面对当前页面造成安全风险 - 给p标签增加
word-break: break-all样式,避免长URL撑破消息气泡 - 原代码中写了遍历逻辑的
useEffect可以直接删除,不需要提前处理聊天数据 - 正则每次执行匹配前重置
lastIndex,避免连续渲染多条消息时出现匹配位置错位的问题
内容的提问来源于stack exchange,提问作者user12102361
相关产品推荐
相关产品推荐

