这是主要的 mixin teritority。首先,我们将定义一个帮助程序来管理样式表。
我们需要一个函数来加载一个样式表,并返回一个成功的Promise。样式表实际上非常疯狂地检测...
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; });
}
好吧 $#!@... 我原以为只是在上面贴上一个加载项,但没有。这是未经测试的,所以如果有任何错误,请更新它——它是从几篇博客文章中编译而来的。
其余的相当简单:
- 允许加载样式表
- 可用时更新状态(以防止 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
}
});
剩下的唯一要做的是在尝试加载之前检查样式表是否已经存在。希望这至少能让你走上正确的道路。