代码之家  ›  专栏  ›  技术社区  ›  Jon Schneider Stefan

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

  •  14
  • Jon Schneider Stefan  · 技术社区  · 7 年前

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

    我尝试的一些方法导致HTML实体被转义。例如 – 按字面形式呈现为“ &恩达斯; “代替as” – ".

    有没有一种方法可以让HTML实体在分配给React道具的JSX动态内容块中呈现unscaped?

    进行的尝试

    尝试使用 template literal :

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

    问题:在渲染输出中 &恩达斯; 从字面上看,被渲染为“ &恩达斯; “代替as” – ".


    试图构造一些没有引号的简单JSX:

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

    问题:此操作在编译时失败,出现语法错误。


    尝试通过将JSX包装在 <span /> 要素:

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

    问题:这是可行的,但我宁愿避免多余的 <跨度/> 渲染输出中存在的元素。


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

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

    问题:

    • 这是可行的,但(在我看来)使代码少了一点 可读。(更明显的是“ndash”而不是“2013” 表示短划线字符。)
    • 此外,这涉及 + -运算符串联,触发 Unexpected string concatenation prefer-template 我的团队JSLint检查器出错;使用字符串插值的解决方案会更好。
    5 回复  |  直到 7 年前
        1
  •  16
  •   Luke Willis Will    7 年前

    你可以避免多余的 span 用一个 Fragment :

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

    此功能在React 16.2中介绍。

    请参见 Documentation


    我同意 @samanime 使用实际字符最适合于简单的情况,但如果您的内容是真正动态的,我更喜欢使用 碎片 entityToChar dangerouslySetInnerHTML 方法。

        2
  •  12
  •   Brett DeWoody    7 年前

    以下是一些选项(我在 general answer 稍后返回):

    1. 最简单-使用Unicode

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

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

      <MyPanel title={`${name} ${String.fromCharCode(8211)} ${description}`} />
      
    3. 万不得已-使用危险的HTML插入原始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
  •  3
  •   samanime    7 年前

    以下是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}`) } />
    
        4
  •  1
  •   Anthony    7 年前

    不知道怎么做 <MyPanel /> 工作,我只能推测你可以做如下事情:

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

    MyPanel。js公司

    render() {
        const { title } = this.props;
    
        return <div dangerouslySetInnerHTML={{ __html: title }} />;
    }
    
        5
  •  0
  •   T.J. Crowder    7 年前

    因为您可能不想在 title 道普,我很想给自己写一个函数 只有 处理将字符实体转换为等效的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>

    请注意 标签 未作为标记输出,但已处理实体。