React Props:使用JSX动态内容中的HTML实体



我有一个反应组件,我想为其提供一个包含JavaScript变量和HTML实体的字符串。

我尝试过的一些方法导致了HTML实体被逃脱。例如,–从字面上渲染为" –",而不是" "。

是否有一种方法可以使HTML实体在分配给React Props的JSX动态内容块中渲染unsced?

尝试

尝试使用模板文字:

<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"代表一个持续的字符。(
  • 此外,这涉及+-操作器串联,这会触发我团队的JSlint检查器中的Unexpected string concatenation prefer-template错误;使用字符串插值的解决方案会更好。

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

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

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

请参阅文档


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

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

  1. 最简单 - 使用Unicode

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

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

    <MyPanel title={`${name} ${String.fromCharCode(8211)} ${description}`} />
    
  3. 最后的度假胜地 - 使用dangesslysetinnerhtml插入RAW HTML。

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

    with:

    <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>

这是html实体上的react文档: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>

mypanel.js

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

,因为您可能不想在title Prop中允许任意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 "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>

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

最新更新