Javascript 使用 React 动态加载样式表
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28386125/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Dynamically load a stylesheet with React
提问by neezer
I'm building a CMS system for managing marketing landing pages. On the "Edit Landing Page" view, I want to be able to load the associated stylesheet for whichever landing page the user is editing. How could I do something like this with React?
我正在构建一个用于管理营销登陆页面的 CMS 系统。在“编辑登陆页面”视图中,我希望能够为用户正在编辑的任何登陆页面加载关联的样式表。我怎么能用 React 做这样的事情?
My app is fully React, isomorphic, running on Koa. My basic component heirarchy for the page in question looks something like this:
我的应用程序完全是 React、同构的,在Koa 上运行。我的相关页面的基本组件层次结构如下所示:
App.jsx (has `<head>` tag)
└── Layout.jsx (dictates page structure, sidebars, etc.)
└── EditLandingPage.jsx (shows the landing page in edit mode)
Data for the landing page (including the path of the stylesheet to load) is fetched asynchronously in EditLandingPagein ComponentDidMount.
登录页面的数据(包括要加载的样式表的路径)在EditLandingPagein 中异步获取ComponentDidMount。
Let me know if you need any additional info. Would love to get this figured out!
如果您需要任何其他信息,请告诉我。很想弄清楚这一点!
Bonus: I'd also like to unload the stylesheet when navigating away from the page, which I assume I can do the reverse of whatever answer comes my way in ComponentWillUnmount, right?
奖励:我还想在离开页面时卸载样式表,我假设我可以做任何答案的相反操作ComponentWillUnmount,对吗?
回答by burakhan alkan
Just update stylesheet's path that you want to be dynamically loaded by using react's state.
只需使用 react 的状态更新您想要动态加载的样式表的路径。
import * as React from 'react';
export default class MainPage extends React.Component{
constructor(props){
super(props);
this.state = {stylePath: 'style1.css'};
}
handleButtonClick(){
this.setState({stylePath: 'style2.css'});
}
render(){
return (
<div>
<link rel="stylesheet" type="text/css" href={this.state.stylePath} />
<button type="button" onClick={this.handleButtonClick.bind(this)}>Click to update stylesheet</button>
</div>
)
}
};
Also, I have implemented it as react component. You can install via npm install react-dynamic-style-loader.
Check my github repository to examine:
https://github.com/burakhanalkan/react-dynamic-style-loader
此外,我已将其实现为反应组件。你可以通过 npm install react-dynamic-style-loader 安装。
检查我的 github 存储库以检查:https:
//github.com/burakhanalkan/react-dynamic-style-loader
回答by Brigand
This is prime mixin teritority. First we'll define a helper to manage style sheets.
这是主要的mixin teritority。首先,我们将定义一个帮助程序来管理样式表。
We need a function that loads a style sheet, and returns a promise for its success. Style sheets are actually pretty insane to detect load on...
我们需要一个函数来加载一个样式表,并返回一个成功的承诺。样式表实际上非常疯狂地检测...
function loadStyleSheet(url){
var sheet = document.createElement('link');
sheet.rel = 'stylesheet';
sheet.href = url;
sheet.type = 'text/css';
document.head.appendChild(sheet);
var _timer;
// TODO: handle failure
return new Promise(function(resolve){
sheet.onload = resolve;
sheet.addEventListener('load', resolve);
sheet.onreadystatechange = function(){
if (sheet.readyState === 'loaded' || sheet.readyState === 'complete') {
resolve();
}
};
_timer = setInterval(function(){
try {
for (var i=0; i<document.styleSheets.length; i++) {
if (document.styleSheets[i].href === sheet.href) resolve();
} catch(e) { /* the stylesheet wasn't loaded */ }
}
}, 250);
})
.then(function(){ clearInterval(_timer); return link; });
}
Well $#!@... I was expecting to just stick an onload on it, but nope. This is untested, so please update it if there are any bugs – it's compiled from several blog articles.
好吧 $#!@... 我原以为只是在上面贴上一个加载项,但没有。这是未经测试的,所以如果有任何错误,请更新它——它是从几篇博客文章中编译而来的。
The rest is fairly straight forward:
其余的相当简单:
- allow loading a stylesheet
- update state when it's available (to prevent FOUC)
- unload any loaded stylesheets when the component unmounts
- handle all the async goodness
- 允许加载样式表
- 可用时更新状态(以防止 FOUC)
- 当组件卸载时卸载所有加载的样式表
- 处理所有异步优点
var mixin = {
componentWillMount: function(){
this._stylesheetPromises = [];
},
loadStyleSheet: function(name, url){
this._stylesheetPromises.push(loadStyleSheet(url))
.then(function(link){
var update = {};
update[name] = true;
this.setState(update);
}.bind(this));
},
componentWillUnmount: function(){
this._stylesheetPromises.forEach(function(p){
// we use the promises because unmount before the download finishes is possible
p.then(function(link){
// guard against it being otherwise removed
if (link.parentNode) link.parentNode.removeChild(link);
});
});
}
};
Again, untested, please update this if there are any issues.
同样,未经测试,如果有任何问题,请更新。
Now we have the component.
现在我们有了组件。
React.createClass({
getInitialState: function(){
return {foo: false};
},
componentDidMount: function(){
this.loadStyleSheet('foo', '/css/views/foo.css');
},
render: function(){
if (!this.state.foo) {
return <div />
}
// return conent that depends on styles
}
});
The only remaining todo is checking if the style sheet already exists before trying to load it. Hopefully this at least gets you on the right path.
剩下的唯一要做的是在尝试加载之前检查样式表是否已经存在。希望这至少能让你走上正确的道路。
回答by Mohamed Magdy
I think that Burakhan answer is correct but it is weird to load <Link href = "" />inside the body tag. That's why I think it should be modified to the following [ I use React hooks]:
我认为 Burakhan 的答案是正确的,但加载<Link href = "" />到 body 标签中很奇怪。这就是为什么我认为应该将其修改为以下内容 [我使用 React hooks]:
import * as React from 'react';
export default MainPage = (props) => {
const [ stylePath, setStylePath ] = useState("style1.css");
const handleButtonClick = () => {
setStylePath({stylePath: 'style2.css'});
}
useEffect(() => {
var head = document.head;
var link = document.createElement("link");
link.type = "text/css";
link.rel = "stylesheet";
link.href = stylePath;
head.appendChild(link);
}, [stylePath]);
return (
<div>
<button type="button" onClick={handleButtonClick}>
Click to update stylesheet
</button>
</div>
);
};
回答by ColdTuna
This is how I add style dynamically:
这就是我动态添加样式的方式:
import React, { Component } from "react";
class MyComponent extends Component {
componentDidMount() {
const cssUrl = "/public/assets/css/style.css";
this.addStyle(cssUrl);
}
addStyle = url => {
const style = document.createElement("link");
style.href = url;
style.rel = "stylesheet";
style.async = true;
document.head.appendChild(style);
};
render() {
return <div> textInComponent </div>;
}
}
export default MyComponent;

