繁体   English   中英

React props:在 JSX 动态内容中使用 HTML 实体?

[英]React props: Using an HTML entity within JSX dynamic content?

我有一个React 组件,我想为它的 props 分配一个包含 JavaScript 变量和 HTML 实体的字符串。

我尝试过的一些方法导致 HTML 实体被转义。 例如, – 被逐字呈现为“ – ”而不是“ ”。

有没有办法让 HTML 实体在分配给 React 道具的 JSX 动态内容块中呈现未转义?

尝试

尝试使用模板文字

<MyPanel title={`${name} &ndash; ${description}`}> ... </MyPanel>

问题:在渲染输出中, &ndash; 字面意思是“ &ndash; ”而不是“ ”。


尝试构造一些不带引号的简单 JSX:

<MyPanel title={{name} &ndash; {description}} ... </MyPanel>

问题:这在编译时因语法错误而失败。


尝试通过将 JSX 包装在<span />元素中来解决语法错误:

<MyPanel title={<span>{name} &ndash; {description}</span>} ... </MyPanel>

问题:这可行,但我宁愿避免渲染输出中出现多余的<span />元素。


尝试用 Unicode 数字字符引用替换 HTML 实体:

<MyPanel title={name + ' \u2013 ' + description} ... </MyPanel>

问题:

  • 这有效,但(在我看来)使代码的可读性稍差。 (更明显的是,“ndash”而不是“2013”​​代表一个破折号字符。)
  • 此外,这涉及+ -operator 连接,这会在我团队的 JSLint 检查器中触发Unexpected string concatenation prefer-template preferred Unexpected string concatenation prefer-template错误; 使用字符串插值的解决方案会更好。

您可以使用Fragment避免多余的span

<MyPanel title={<>{name} &ndash; {description}</>} ... </MyPanel>

这个特性是在 React 16.2 中引入的。

查看文档


我同意@samanime 的观点,即使用实际字符最适合简单情况,但如果您的内容确实是动态的,我更愿意使用Fragment而不是entityToChardangerouslySetInnerHTMLentityToChar方法。

这里有一些选项(我在不久前的一个更一般的答案中概述了这些):

  1. 最简单 - 使用 Unicode

     <MyPanel title={ `${name} – ${description}` } />
  2. 更安全 - 对 Javascript 字符串中的实体使用 Unicode 编号。

     <MyPanel title={`${name} \– ${description}`} />

    或者

    <MyPanel title={`${name} ${String.fromCharCode(8211)} ${description}`} />
  3. 最后的手段 - 使用危险的 SetInnerHTML 插入原始 HTML。

     title={`${name} &ndash; ${description}`}

    和:

     <div dangerouslySetInnerHTML={{__html: props.title}}></div> 

 const MyPanel = (props) => { return ( <div>{props.title}</div> ) } const MyPanelwithDangerousHTML = (props) => { return ( <div dangerouslySetInnerHTML={{__html: props.title}}></div> ) } var description = "description"; var name = "name"; ReactDOM.render(<MyPanel title={`${name} – ${description}`} /> , document.getElementById("option1")); ReactDOM.render(<MyPanel title={`${name} \– ${description}`} /> , document.getElementById("option2")); ReactDOM.render(<MyPanel title={`${name} ${String.fromCharCode(8211)} ${description}`} /> , document.getElementById("option3")); ReactDOM.render(<MyPanelwithDangerousHTML title={`${name} &ndash; ${description}`} /> , document.getElementById("option4"));
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.js"></script> <div id="option1"></div> <div id="option2"></div> <div id="option3"></div> <div id="option4"></div>

这是 React 关于 HTML 实体的文档: JSX Gotchas

其中,最好使用实际字符而不是 HTML 实体:

<MyPanel title={ `${name} – ${description}` } />

如果因为 HTML 实体是动态的(它不仅仅是硬编码的短划线)而不能这样做,则可以翻译该实体。 这是一个可以做到这一点的小函数:

const entityToChar = str => { 
  const textarea = document.createElement('textarea'); 
  textarea.innerHTML = str; 
  return textarea.value; 
}

然后像这样使用它:

<MyPanel title={ entityToChar(`${name} &ndash; ${description}`) } />

在不知道<MyPanel />是如何工作的情况下,我只能推测您可以执行以下操作:

<MyPanel title={`${name} &ndash; ${description}`}> ... </MyPanel>

我的面板.js

render() {
    const { title } = this.props;

    return <div dangerouslySetInnerHTML={{ __html: title }} />;
}

由于您可能不希望在您的title道具中允许任意 URL,因此我很想为自己编写一个函数,该函数处理将字符实体转换为等效的 Unicode 字符。 有点像“HTML-lite”。 :-) 没有那么多命名引用,真的; 数字很​​简单:

const named = {
  "ndash": "–", // or "\u2013"
  "mdash": "—", // or "\u2014"
  "nbsp": " "   // or "\u00A0"
  // ...
};
// Obviously this is a SKETCH, not production code!
function convertCharEntities(str) {
  return str.replace(/&([^ ;&]+);/g, (_, ref) => {
    let ch;
    if (ref[0] === "#") {
      let num;
      if (ref[0].toLowerCase() === "x") {
        num = parseInt(ref.substring(2), 16);
      } else {
        num = parseInt(ref, 10);
      }
      ch = String.fromCodePoint(num);
    } else {
      ch = named[ref.toLowerCase()];
    }
    return ch || "";
  });
}

然后在渲染该道具时使用它:

class Example extends React.Component {
  render() {
    return <div>{convertCharEntities(this.props.title || "")}</div>;
  }
}

完整的现场示例:

 const named = { "ndash": "–", // or "\–" "mdash": "—", // or "\—" "nbsp": " " // or "\ " // ... }; // Obviously this is a SKETCH, not production code! function convertCharEntities(str) { return str.replace(/&([^ ;&]+);/g, (_, ref) => { let ch; if (ref[0] === "#") { let num; if (ref[0].toLowerCase() === "x") { num = parseInt(ref.substring(2), 16); } else { num = parseInt(ref, 10); } ch = String.fromCodePoint(num); } else { ch = named[ref.toLowerCase()]; } return ch || ""; }); } class Example extends React.Component { render() { return <div>{convertCharEntities(this.props.title || "")}</div>; } } ReactDOM.render( <Example title="Testing&nbsp;1&#160;2&#xa0;3&nbsp;&mdash; enh, you know the drill <script src='nefarious.js'><\\/script>" />, document.getElementById("root") );
 <div id="root"></div><script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

请注意,标签不是作为标签输出,而是处理实体。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM