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