稍后动态插入Javascript:如何让它运行?

Nic*_*ick 11 javascript reactjs dangerouslysetinnerhtml

我的 React 应用程序中有脚本,稍后会动态插入。脚本不加载。

\n

在我的数据库中有一个名为 的字段content,其中包含包含 html 和 javascript 的数据。有很多记录,每个记录可以包含该content字段中的多个脚本。因此,在我的 React 应用程序中静态指定每个脚本 URL 并不是真正的选项。例如,记录的字段可能如下所示:

\n
<p>Some text and html</p>\n<div id="xxx_hype_container">\n    <script type="text/javascript" charset="utf-8" src="https://example.com/uploads/hype_generated_script.js?499892"></script>\n</div>\n<div style="display: none;" aria-hidden="true"> \n<div>Some text.</div> \nEtc\xe2\x80\xa6\n
Run Code Online (Sandbox Code Playgroud)\n

我使用以下命令在我的 React 应用程序中调用此字段dangerouslySetInnerHTML

\n
render() {\n    return (\n        <div data-page="clarifies">\n            <div className="container">\n                <div dangerouslySetInnerHTML={{ __html: post.content }} />\n                ... some other data\n            </div>\n        </div>\n    );\n}\n
Run Code Online (Sandbox Code Playgroud)\n

它正确地从数据库加载数据并显示该数据的 html。但是,Javascript 不会被执行。我认为该脚本不起作用,因为它是稍后动态插入的。我怎样才能让这些脚本工作/运行?

\n

这篇文章提出了动态插入脚本的解决方案,但我不认为我可以应用此解决方案,因为在我的情况下,脚本/代码是从数据库插入的(那么如何在nodeScriptReplace代码上使用...?)。有什么建议可以让我的脚本发挥作用吗?

\n
\n

更新回应 @lissettdm 他们的答案:

\n
constructor(props) {\n    this.ref = React.createRef();\n}\n\ncomponentDidUpdate(prevProps, prevState) {\n    if (prevProps.postData !== this.props.postData) {\n        this.setState({\n            loading: false,\n            post: this.props.postData.data,\n            //etc\n        });\n        setTimeout(() => parseElements());\n\n        console.log(this.props.postData.data.content);\n        // returns html string like: `<div id="hype_container" style="margin: auto; etc.`\n        const node = document.createRange().createContextualFragment(this.props.postData.data.content);\n        console.log(JSON.stringify(this.ref));\n        // returns {"current":null}\n        console.log(node);\n        // returns [object DocumentFragment]\n        this.ref.current.appendChild(node);\n        // produces error "Cannot read properties of null"\n    }\n}\n\nrender() {\n    const { history } = this.props;\n    /etc.\n    return (\n        {loading ? (\n            some code\n        ) : (\n            <div data-page="clarifies">\n                <div className="container">\n                    <div ref={this.ref}></div>\n                    ... some other data\n                </div>\n            </div>\n        );\n    );\n}\n
Run Code Online (Sandbox Code Playgroud)\n

this.ref.current.appendChild(node);行产生错误:

\n
\n

类型错误:无法读取 null 的属性(读取“appendChild”)

\n
\n

lis*_*tdm 4

如果您确定 HTML 字符串内容是安全的并且包含具有有效 HTML 的字符串,您可以使用Range.createContextualFragment()(执行脚本)

function App() {
  const ref = useRef();

  useEffect(() => {
    /* convert your HTML string into DocumentFragment*/
    const node = document.createRange().createContextualFragment(HTML);
    ref.current.appendChild(node);
  }, []);

  return (
    <div>
      <h1>HTML String</h1>
      <div>
        <div ref={ref}></div>
      </div>
    </div>
  );
}

Run Code Online (Sandbox Code Playgroud)

查看内容如何在 JavaScript 控制台工作示例script上执行

如果您在类构造函数中使用class component创建ref,然后更新节点内容,我这样做componentDidMount只是为了测试:

class App extends React.Component {
  constructor(props) {
    super(props);
    this.ref = React.createRef();
  }

  componentDidMount() {
    const node = document.createRange().createContextualFragment(HTML);
    this.ref.current.appendChild(node);
  }

  render() {
    return (
      <div>
        <h1>HTML String</h1>
        <div>
          <div ref={this.ref}></div>
        </div>
      </div>
    );
  }
}

Run Code Online (Sandbox Code Playgroud)

看这个工作示例

  • 嗨@Nick,类组件有点不同,我更新了我的答案 (2认同)