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

如何在React.js博客的textarea中安全实现文本内可点击链接功能

React博客安全实现可点击链接的方案

推荐三种安全可行的实现方式,按安全程度和易用性排序如下:


1. 自定义标记语法解析(最安全)

让用户使用类似 [链接文本](目标URL) 的轻量标记语法输入链接,然后自己编写解析函数将文本转换为React元素,完全避免使用dangerouslySetInnerHTML,从根源杜绝代码注入风险。

代码示例

import { useState } from 'react';

// 解析带自定义标记的文本,生成React元素数组
const parseTextWithLinks = (text) => {
  // 匹配 [文本](https://xxx) 格式的正则
  const linkRegex = /\[([^\]]+)\]\((https?:\/\/[^\)]+)\)/g;
  const parts = [];
  let lastIndex = 0;
  let match;

  while ((match = linkRegex.exec(text)) !== null) {
    // 添加链接前的普通文本
    if (match.index > lastIndex) {
      parts.push(text.slice(lastIndex, match.index));
    }
    // 添加安全的链接元素
    parts.push(
      <a 
        key={match.index} 
        href={match[2]} 
        target="_blank" 
        rel="noopener noreferrer"
        style={{ color: '#0066cc', textDecoration: 'underline' }}
      >
        {match[1]}
      </a>
    );
    lastIndex = linkRegex.lastIndex;
  }

  // 添加剩余的普通文本
  if (lastIndex < text.length) {
    parts.push(text.slice(lastIndex));
  }

  return parts;
};

const BlogEditor = () => {
  const [content, setContent] = useState('');

  return (
    <div>
      <textarea
        value={content}
        onChange={(e) => setContent(e.target.value)}
        placeholder="使用 [链接文本](URL) 格式插入链接"
        rows={10}
        style={{ width: '100%' }}
      />
      <div style={{ marginTop: '20px', padding: '10px', border: '1px solid #eee' }}>
        {parseTextWithLinks(content)}
      </div>
    </div>
  );
};

export default BlogEditor;

2. DOMPurify 配合 dangerouslySetInnerHTML

如果需要允许用户直接输入HTML格式的链接(比如<a href="xxx">文本</a>),必须先通过HTML净化库过滤恶意代码,再使用dangerouslySetInnerHTML渲染。

代码示例

import { useState } from 'react';
import DOMPurify from 'dompurify';

const BlogEditor = () => {
  const [content, setContent] = useState('');

  // 严格净化用户输入,只保留允许的标签和属性
  const sanitizedContent = DOMPurify.sanitize(content, {
    ADD_TAGS: ['a'],
    ADD_ATTR: ['href'],
    FORBID_ATTR: ['onclick', 'onload', 'onerror'],
    ALLOWED_PROTOCOLS: ['http', 'https']
  });

  return (
    <div>
      <textarea
        value={content}
        onChange={(e) => setContent(e.target.value)}
        placeholder="直接输入 <a href='URL'>链接文本</a> 格式的内容"
        rows={10}
        style={{ width: '100%' }}
      />
      <div 
        style={{ marginTop: '20px', padding: '10px', border: '1px solid #eee' }}
        dangerouslySetInnerHTML={{ __html: sanitizedContent }}
      />
    </div>
  );
};

export default BlogEditor;

3. 使用成熟的富文本编辑器

直接集成现成的富文本编辑器组件(如Draft.js、Slate),这类组件会将内容以结构化JSON格式存储,渲染时直接转换为安全的React元素,用户通过UI按钮插入链接,无需手动输入标记或HTML,体验和安全性兼顾。

简化示例(Draft.js)

import { useState } from 'react';
import { Editor, EditorState, RichUtils } from 'draft-js';
import 'draft-js/dist/Draft.css';

const BlogEditor = () => {
  const [editorState, setEditorState] = useState(EditorState.createEmpty());

  // 触发插入链接的UI逻辑
  const handleInsertLink = () => {
    const url = prompt('请输入链接地址:');
    if (!url) return;
    const contentState = editorState.getCurrentContent();
    const selection = editorState.getSelection();
    const newContentState = RichUtils.toggleLink(
      contentState,
      selection,
      url
    );
    setEditorState(EditorState.push(editorState, newContentState, 'toggle-link'));
  };

  return (
    <div>
      <button onClick={handleInsertLink} style={{ marginBottom: '10px' }}>
        插入链接
      </button>
      <Editor
        editorState={editorState}
        onChange={setEditorState}
        placeholder="撰写博客内容,点击按钮插入链接"
        style={{ border: '1px solid #eee', padding: '10px', minHeight: '200px' }}
      />
    </div>
  );
};

export default BlogEditor;

方案对比

  • 自定义标记解析:安全性最高,完全可控,适合需求简单的场景,但需要自行维护解析逻辑。
  • DOMPurify方案:适合允许HTML输入的场景,通过严格规则降低风险,但依赖第三方库。
  • 富文本编辑器:用户体验最好,内置安全处理,适合复杂编辑需求,但会增加项目体积。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 14:01:38