用React动态加载样式表

问题描述 投票:17回答:3

我正在建立一个CMS系统来管理营销目标网页。在“编辑登录页面”视图上,我希望能够为用户正在编辑的任何登录页面加载相关的样式表。我该如何使用React做类似的事情?

我的应用程序完全是React,同构,在Koa上运行。我所讨论页面的基本组件层次结构如下所示:

App.jsx (has `<head>` tag)
└── Layout.jsx (dictates page structure, sidebars, etc.)
    └── EditLandingPage.jsx (shows the landing page in edit mode)

登录页面的数据(包括要加载的样式表的路径)是在EditLandingPage中的ComponentDidMount中异步获取的。

让我知道您是否需要其他信息。很想弄清楚这个问题!

奖金:我也想在离开页面时卸载样式表,我想我可以像ComponentWillUnmount中给出的任何答案相反,对吗?

javascript stylesheet reactjs isomorphic-javascript
3个回答
23
投票
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> ) } };

而且,我已经将其实现为react组件。您可以通过npm install react-dynamic-style-loader安装。检查我的github存储库以检查:https://github.com/burakhanalkan/react-dynamic-style-loader


7
投票
我们需要一个加载样式表并返回成功承诺的函数。样式表实际上很疯狂,无法检测到负载...

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 $#!@ ...我本来只是希望在它上面加一个加载,但不。这未经测试,因此,如果有任何错误,请对其进行更新–它是根据几篇博客文章编译而成的。

其余的内容很简单:

允许加载样式表

    在可用时更新状态(以防止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); }); }); } };
  • 再次,未经测试,如果有任何问题,请对此进行更新。
    现在我们有了组件。

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

    唯一剩下的待办事项是在尝试加载样式表之前检查样式表是否已经存在。希望这至少可以使您走上正确的道路。


  • 0
    投票
    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> ); };
    © www.soinside.com 2019 - 2024. All rights reserved.