我有一个相对简单的问题,试图将内联脚本添加到React组件。到目前为止我有:

'use strict';

import '../../styles/pages/people.scss';

import React, { Component } from 'react';
import DocumentTitle from 'react-document-title';

import { prefix } from '../../core/util';

export default class extends Component {
    render() {
        return (
            <DocumentTitle title="People">
                <article className={[prefix('people'), prefix('people', 'index')].join(' ')}>
                    <h1 className="tk-brandon-grotesque">People</h1>
                    
                    <script src="https://use.typekit.net/foobar.js"></script>
                    <script dangerouslySetInnerHTML={{__html: 'try{Typekit.load({ async: true });}catch(e){}'}}></script>
                </article>
            </DocumentTitle>
        );
    }
};

我也试过:

<script src="https://use.typekit.net/foobar.js"></script>
<script>try{Typekit.load({ async: true });}catch(e){}</script>

这两种方法似乎都不能执行所需的脚本。我猜我错过了一件简单的事。有人能帮忙吗?

PS:忽略foobar,我有一个真正的id实际上在使用,我不想分享。


当前回答

要在head tag <head>中添加脚本标签或代码,请使用react-helmet包。它很轻,有很好的文档。

在script标签中添加Js代码

    function htmlDecode(html) {
      return html.replace(/&([a-z]+);/ig, (match, entity) => {
        const entities = { amp: '&', apos: '\'', gt: '>', lt: '<', nbsp: '\xa0', quot: '"' };
        entity = entity.toLowerCase();
        if (entities.hasOwnProperty(entity)) {
          return entities[entity];
        }
        return match;
      });
    }
  render() {
    const scriptCode = `<script type="text/javascript">
          {(function() {
          window.hello={
            FIRST_NAME: 'firstName',
            LAST_NAME: 'lastName',
          };
          })()}
          </script>`
    return(
      <div dangerouslySetInnerHTML={{ __html: this.htmlDecode(scriptCode) }} />;
    );
  }

这段代码可以通过console.log(windows.hello)进行测试。

其他回答

Alex Mcmillan提供的答案对我帮助最大,但对于更复杂的脚本标记不太适用。

我稍微调整了他的答案,提出了一个解决方案的长标签与各种功能,另外已经设置“src”。

(对于我的用例,脚本需要生活在头部,这是反映在这里):

  componentWillMount () {
      const script = document.createElement("script");

      const scriptText = document.createTextNode("complex script with functions i.e. everything that would go inside the script tags");

      script.appendChild(scriptText);
      document.head.appendChild(script);
  }

有点晚了,但我决定创建我自己的@Alex Macmillan的答案后,这是通过传递两个额外的参数;放置脚本的位置,如或和设置async为true/false,这里是:

import { useEffect } from 'react';

const useScript = (url, position, async) => {
  useEffect(() => {
    const placement = document.querySelector(position);
    const script = document.createElement('script');

    script.src = url;
    script.async = typeof async === 'undefined' ? true : async;

    placement.appendChild(script);

    return () => {
      placement.removeChild(script);
    };
  }, [url]);
};

export default useScript;

调用它的方式与本文中接受的答案完全相同,但有两个额外的参数(再次):

// First string is your URL
// Second string can be head or body
// Third parameter is true or false.
useScript("string", "string", bool);

只需在HTML文件中添加主体

<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>

你可以试着使用下面的语句:

确保你相信剧本

 <script>{`
            function myFunction(index, row) {
                return index;
            }
        `}
</script>

使用Range.createContextualFragment有一个很好的变通方法。

/**
 * Like React's dangerouslySetInnerHTML, but also with JS evaluation.
 * Usage:
 *   <div ref={setDangerousHtml.bind(null, html)}/>
 */
function setDangerousHtml(html, el) {
    if(el === null) return;
    const range = document.createRange();
    range.selectNodeContents(el);
    range.deleteContents();
    el.appendChild(range.createContextualFragment(html));
}

这适用于任意HTML,也保留上下文信息,如document.currentScript。