将脚本标签添加到React / JSX

2020/10/07 00:21 · javascript ·  · 0评论

我有一个相对直接的问题,试图将内联脚本添加到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正在使用中,我不想共享。

编辑:事情变化很快,这已经过时了-查看更新


您是否想在每次渲染此组件时一次或一次将该组件安装到DOM中时一次又一次地获取并执行脚本?

也许尝试这样的事情:

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

    script.src = "https://use.typekit.net/foobar.js";
    script.async = true;

    document.body.appendChild(script);
}

但是,这仅在要加载的脚本不能作为模块/软件包提供时才真正有用。首先,我将始终:

  • npm上寻找包裹
  • 在我的专案中下载并安装套件(npm install typekit
  • import我需要的包装(import Typekit from 'typekit';

这可能是您安装软件包的方式react以及react-document-title您的示例,并且npm上有一个Typekit软件包


更新:

现在我们有了钩子,更好的方法可能是这样使用useEffect

useEffect(() => {
  const script = document.createElement('script');

  script.src = "https://use.typekit.net/foobar.js";
  script.async = true;

  document.body.appendChild(script);

  return () => {
    document.body.removeChild(script);
  }
}, []);

这使其成为自定义钩子的理想选择(例如:)hooks/useScript.js

import { useEffect } from 'react';

const useScript = url => {
  useEffect(() => {
    const script = document.createElement('script');

    script.src = url;
    script.async = true;

    document.body.appendChild(script);

    return () => {
      document.body.removeChild(script);
    }
  }, );
};

export default useScript;

可以这样使用:

import useScript from 'hooks/useScript';

const MyComponent = props => {
  useScript('https://use.typekit.net/foobar.js');

  // rest of your component
}

除了上述答案,您还可以执行以下操作:

import React from 'react';

export default class Test extends React.Component {
  constructor(props) {
    super(props);
  }

  componentDidMount() {
    const s = document.createElement('script');
    s.type = 'text/javascript';
    s.async = true;
    s.innerHTML = "document.write('This is output by document.write()!')";
    this.instance.appendChild(s);
  }

  render() {
    return <div ref={el => (this.instance = el)} />;
  }
}

div已绑定,this脚本已注入其中。

演示可以在codesandbox.io找到

我最喜欢的方法是使用React Helmet(反应头盔)–它是一个组件,可以以您可能已经习惯的方式轻松操作文档头。

例如

import React from "react";
import {Helmet} from "react-helmet";

class Application extends React.Component {
  render () {
    return (
        <div className="application">
            <Helmet>
                <script src="https://use.typekit.net/foobar.js"></script>
                <script>try{Typekit.load({ async: true });}catch(e){}</script>
            </Helmet>
            ...
        </div>
    );
  }
};

https://github.com/nfl/react-helmet

如果您需要<script>在SSR(服务器端渲染)中使用块,则使用的方法componentDidMount将不起作用。

您可以改用react-safe库。React中的代码将是:

import Safe from "react-safe"

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

亚历克斯·麦克米伦(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);
  }

我为此特定情况创建了一个React组件:https : //github.com/coreyleelarson/react-typekit

只需传递您的Typekit套件ID作为道具,就可以了。

import React from 'react';
import Typekit from 'react-typekit';

const HtmlLayout = () => (
  <html>
    <body>
      <h1>My Example React Component</h1>
      <Typekit kitId="abc123" />
    </body>
  </html>
);

export default HtmlLayout;

有一个非常好的解决方法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

您还可以使用反应头盔

import React from "react";
import {Helmet} from "react-helmet";

class Application extends React.Component {
  render () {
    return (
        <div className="application">
            <Helmet>
                <meta charSet="utf-8" />
                <title>My Title</title>
                <link rel="canonical" href="http://example.com/example" />
                <script src="/path/to/resource.js" type="text/javascript" />
            </Helmet>
            ...
        </div>
    );
  }
};

头盔采用纯HTML标记并输出纯HTML标记。这简直太简单了,而且React初学者也很友好。

您可以用来npm postscribe在react组件中加载脚本

postscribe('#mydiv', '<script src="https://use.typekit.net/foobar.js"></script>')

您可以在以下链接中找到最佳答案:

https://cleverbeagle.com/blog/articles/tutorial-how-to-load-third-party-scripts-dynamically-in-javascript

const loadDynamicScript = (callback) => {
const existingScript = document.getElementById('scriptId');

if (!existingScript) {
    const script = document.createElement('script');
    script.src = 'url'; // URL for the third-party library being loaded.
    script.id = 'libraryName'; // e.g., googleMaps or stripe
    document.body.appendChild(script);

    script.onload = () => {
      if (callback) callback();
    };
  }

  if (existingScript && callback) callback();
};

对于多个脚本,请使用此

var loadScript = function(src) {
  var tag = document.createElement('script');
  tag.async = false;
  tag.src = src;
  document.getElementsByTagName('body').appendChild(tag);
}
loadScript('//cdnjs.com/some/library.js')
loadScript('//cdnjs.com/some/other/library.js')
componentDidMount() {
  const head = document.querySelector("head");
  const script = document.createElement("script");
  script.setAttribute(
    "src",
    "https://assets.calendly.com/assets/external/widget.js"
  );
  head.appendChild(script);
}

根据Alex McMillan的解决方案,我进行了以下调整。

我自己的环境:React 16.8+,下一个v9 +

//添加一个名为Script的自定义组件

// hooks / Script.js

import { useEffect } from 'react'

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

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

    document.body.appendChild(script)

    return () => {
      document.body.removeChild(script)
    }
  }, )
}

export default function Script({ src, async=true}) {

  useScript(src, async)

  return null  // Return null is necessary for the moment.
}

//使用自定义组件,只需将其导入并<script>用自定义驼峰<Script>标签替换旧的小写标签即可

// index.js

import Script from "../hooks/Script";

<Fragment>
  {/* Google Map */}
  <div ref={el => this.el = el} className="gmap"></div>

  {/* Old html script */}
  {/*<script type="text/javascript" src="http://maps.google.com/maps/api/js"></script>*/}

  {/* new custom Script component */}
  <Script src='http://maps.google.com/maps/api/js' async={false} />
</Fragment>

参加聚会有点晚了,但我决定在查看@Alex Macmillan答案后创建自己的一个,那就是通过传递两个额外的参数;放置脚本(例如或)并将异步设置为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);
    };
  }, );
};

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

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

要在主体中的脚本标签中添加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)

解决方案取决于方案。就像我的情况一样,我必须在calendar组件中加载嵌入的日历。

Calendly寻找一个div并读取其data-url属性,然后在该div中加载一个iframe。

第一次加载页面时,一切都很好:首先,data-url呈现div with 然后将日历脚本添加到正文中。浏览器下载并评估它,我们都很高兴。

当您导航离开然后回到页面时,问题就来了。这次脚本仍然存在,浏览器不会重新下载并重新评估它。

固定:

  1. componentWillUnmount找到并删除脚本元素。然后在重新安装时,重复上述步骤。
  2. 输入$.getScript这是一个漂亮的jquery助手,它带有脚本URI和成功回调。脚本加载后,将对其进行评估并触发您的成功回调。我要做的就是在我的componentDidMount $.getScript(url)我的render方法已经有了可扩展的div。而且工作顺利。
本文地址:http://javascript.askforanswer.com/jiangjiaobenbiaoqiantianjiadaoreact-jsx.html
文章标签: ,   ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!