Arr*_*ght 197 javascript ecmascript-6 reactjs react-jsx
我有一个相对简单的问题,试图将内联脚本添加到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>
);
}
};
Run Code Online (Sandbox Code Playgroud)
我也尝试过:
<script src="https://use.typekit.net/foobar.js"></script>
<script>try{Typekit.load({ async: true });}catch(e){}</script>
Run Code Online (Sandbox Code Playgroud)
这两种方法似乎都没有执行所需的脚本.我猜这是一件我想念的简单事.有人可以帮忙吗?
PS:忽略foobar,我有一个真正的ID实际上在使用,我不想分享.
Ale*_*lan 289
是否要在每次渲染此组件时一次又一次地获取和执行脚本,或者只是在将此组件装入DOM时只执行一次?
也许尝试这样的事情:
componentDidMount () {
const script = document.createElement("script");
script.src = "https://use.typekit.net/foobar.js";
script.async = true;
document.body.appendChild(script);
}
Run Code Online (Sandbox Code Playgroud)
但是,如果要加载的脚本不可用作模块/包,这只是非常有用.首先,我会永远:
npm install typekit)import我需要的包裹(import Typekit from 'typekit';)这可能是您安装软件包的方式react,也可能是您react-document-title的示例,并且npm上有一个Typekit软件包.
sid*_*son 49
继上面的答案,你可以这样做:
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)} />;
}
}
Run Code Online (Sandbox Code Playgroud)
div被绑定this并且脚本被注入其中.
可以在codesandbox.io上找到演示
Pat*_*rex 40
我最喜欢的方法是使用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>
);
}
};
Run Code Online (Sandbox Code Playgroud)
https://github.com/nfl/react-helmet
Div*_*ani 13
这样的回答解释了为什么这种行为背后。
任何方式来呈现的script预期标签不工作:
script标签用于外部脚本dangerouslySetInnerHTMLReact DOM(react on web 的渲染器)使用createElement调用将 JSX 渲染为 DOM 元素。
createElement使用innerHTMLDOM API 最终将这些添加到 DOM(参见 React 源代码中的代码)。innerHTML 不执行script作为安全考虑添加的标签。这就是为什么script在 React 中渲染标签不能按预期工作的原因。
有关如何script在 React 中使用标签,请查看此页面上的其他一些答案。
小智 11
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);
}
Run Code Online (Sandbox Code Playgroud)
sca*_*aza 10
如果你需要<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>
Run Code Online (Sandbox Code Playgroud)
您也可以使用反应头盔
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>
);
}
};
Run Code Online (Sandbox Code Playgroud)
Helmet 采用纯 HTML 标签并输出纯 HTML 标签。它非常简单,而且 React 初学者友好。
我为这个特定的案例创建了一个React组件:https://github.com/coreyleelarson/react-typekit
只需将你的Typekit Kit 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;
Run Code Online (Sandbox Code Playgroud)
以下是我最终能够在 React JS 代码中添加两个外部 JavaScript 文件的方法:
这些是我遵循的步骤。
第1步:
我在react-app文件夹路径中使用终端安装了React-Helmet 。npm i react-helmet
第 2 步:
然后我import {Helmet} from "react-helmet";在代码中添加了标头。
第 3 步:最后,在我的代码中,这就是我使用Helment 添加外部 JS 文件的方式
<Helmet>
<script src = "path/to/my/js/file1.js" type = "text/javascript" />
<script src = "path/to/my/js/file2.js" type = "text/javascript" />
</Helmet>
Run Code Online (Sandbox Code Playgroud)
有一个非常好的解决方法,使用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));
}
Run Code Online (Sandbox Code Playgroud)
这适用于任意 HTML 并保留上下文信息,例如document.currentScript.
我试图编辑@Alex McMillan 接受的答案,但它不会让我如此这里有一个单独的答案,您可以在其中获得您加载的库的价值。人们要求的一个非常重要的区别,我需要我的使用 stripe.js 实现。
import { useState, useEffect } from 'react'
export const useScript = (url, name) => {
const [lib, setLib] = useState({})
useEffect(() => {
const script = document.createElement('script')
script.src = url
script.async = true
script.onload = () => setLib({ [name]: window[name] })
document.body.appendChild(script)
return () => {
document.body.removeChild(script)
}
}, [url])
return lib
}
Run Code Online (Sandbox Code Playgroud)
用法看起来像
const PaymentCard = (props) => {
const { Stripe } = useScript('https://js.stripe.com/v2/', 'Stripe')
}
Run Code Online (Sandbox Code Playgroud)
注意:将库保存在对象中,因为通常库是一个函数,而 React 将在存储状态时执行该函数以检查更改——这将破坏期望使用特定参数调用的库(如 Stripe)——所以我们将它存储在一个对象中以对 React 隐藏它并保护库函数不被调用。
您可以使用npm postscribe在反应组件中加载脚本
postscribe('#mydiv', '<script src="https://use.typekit.net/foobar.js"></script>')
Run Code Online (Sandbox Code Playgroud)
小智 5
您可以通过以下链接找到最佳答案:
Run Code Online (Sandbox Code Playgroud)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(); };
要在 head 标签中添加脚本标签或代码<head>,请使用react-helmet包。它很轻并且有很好的文档。
要在body内的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) }} />;
);
}
Run Code Online (Sandbox Code Playgroud)
这段代码可以通过以下方式测试console.log(windows.hello)
与其他答案非常相似,只是使用默认值来清理未定义的检查
import { useEffect } from 'react'
const useScript = (url, selector = 'body', async = true) => {
useEffect(() => {
const element = document.querySelector(selector)
const script = document.createElement('script')
script.src = url
script.async = async
element.appendChild(script)
return () => {
element.removeChild(script)
}
}, [url])
}
export default useScript
Run Code Online (Sandbox Code Playgroud)
用法
useScript('/path/to/local/script.js') // async on body
useScript('https://path/to/remote/script.js', 'html') // async on html
useScript('/path/to/local/script.js', 'html', false) // not async on html.. e.g. this will block
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
254374 次 |
| 最近记录: |