【问题标题】:React props: Using an HTML entity within JSX dynamic content?React props:在 JSX 动态内容中使用 HTML 实体?
【发布时间】:2018-07-26 13:48:41
【问题描述】:

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

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

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

尝试

尝试使用template literal

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

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


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

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

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


尝试通过将 JSX 包装在 &lt;span /&gt; 元素中来解决语法错误:

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

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


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

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

问题:

  • 这可行,但(在我看来)使代码少了一点 可读。 (更明显的是“ndash”而不是“2013” 表示一个短划线字符。)
  • 此外,这涉及+-operator 连接,这会在我团队的JSLint 检查器中触发Unexpected string concatenation prefer-template 错误;使用字符串插值的解决方案会更好。

【问题讨论】:

  • dangerouslySetInnerHTML&lt;MyPanel /&gt; 的子元素是否有效?
  • 将其赋值给一个变量,然后使用它:let temp_str = ${name} – ${描述}``
  • @Tony:它被用于title 属性中。
  • @Tony:你可能是对的,因为 span 已经工作了。但是,在 prop 中允许 HTML 然后使用 dangerouslySetInnerHTML 会......很危险。 :-D
  • @T.J.Crowder 哦,绝对是!

标签: javascript reactjs


【解决方案1】:

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

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

此功能是在 React 16.2 中引入的。

Documentation


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

【讨论】:

    【解决方案2】:

    这里有几个选项(我在不久前的 general answer 中概述了这些选项):

    1. 最简单 - 使用 Unicode

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

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

      <MyPanel title={`${name} ${String.fromCharCode(8211)} ${description}`} />
      
    3. 最后的手段 - 使用 dangerouslySetInnerHTML 插入原始 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} \u2013 ${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>

    【讨论】:

      【解决方案3】:

      这是 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}`) } />
      

      【讨论】:

      • 问题是,当然,就像dangerouslySetInnerHTML,这意味着组件很高兴地渲染它通过props 接收到的HTML 内容,就像dangerouslySetInnerHTML,是...危险的。 :-)
      • 它比dangerouslySetInnerHTML 好一点,因为它会以textarea 的值返回,这会去掉很多HTML。
      【解决方案4】:

      在不知道&lt;MyPanel /&gt; 的工作原理的情况下,我只能推测您可以执行以下操作:

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

      MyPanel.js

      render() {
          const { title } = this.props;
      
          return <div dangerouslySetInnerHTML={{ __html: title }} />;
      }
      

      【讨论】:

        【解决方案5】:

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

        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 "\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>;
          }
        }
        
        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>

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

        【讨论】:

          猜你喜欢
          • 2018-04-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-24
          • 2020-08-18
          • 2023-04-01
          • 1970-01-01
          • 2017-07-27
          相关资源
          最近更新 更多