![qt 加载样式表](https://i-blog.csdnimg.cn/blog_migrate/20bbcb2399dbb3f47908fb8a85cedee9.png)
qt 加载样式表
Often we want to load a CSS file on-demand by inserting a link
node. And we want to know when the file finished loading in order to call a callback function for example.
通常,我们想通过插入link
节点来按需加载CSS文件。 而且我们想知道文件何时完成加载,以调用回调函数。
Long story short: turns out this is harder than it should be and really unnecessary hard in Firefox. I hereby beg on behalf of many frustrated developers: please, Firefox 4, please fire a load
event when a stylesheet loads.
长话短说:事实证明,这比应该做的难,而且在Firefox中确实不必要。 我在此代表许多沮丧的开发人员: Firefox 4,请在load
样式表时触发load
事件。
load
event on
link
elements as the
HTML5 standard mandates. Here's the list of bugs for each browser to comment on and point people to:
Here's what the standard says:
"Once the attempts to obtain the resource and its critical subresources are complete, the user agent must, if the loads were successful, queue a task to fire a simple event named
load
at thelink
element"
link
元素上触发
load
事件。 这是每个浏览器要评论并指出人们的错误列表:
标准是这样的:
“一旦完成了获取资源及其关键子资源的尝试,如果加载成功,则用户代理必须将任务排队,以在
link
元素处触发一个名为load
的简单事件。”
With that out of the way, let's see what we have here.
顺便说一句,让我们看看这里有什么。
// my callback function
// which relies on CSS being loaded
function CSSDone() {
alert('zOMG, CSS is done');
}
// load me some stylesheet
var url = "http://tools.w3clubs.com/pagr/1.sleep-1.css",
head = document.getElementsByTagName('head')[0];
link = document.createElement('link');
link.type = "text/css";
link.rel = "stylesheet"
link.href = url;
// MAGIC
// call CSSDone() when CSS arrives
head.appendChild(link);
Options for the magic part, sorted from nice-and-easy to ridiculous
魔术部分的选项,从容易到荒谬
listen to
link.onload
听
link.onload
listen to
link.addEventListener('load')
听
link.addEventListener('load')
listen to
link.onreadystatechange
听
link.onreadystatechange
setTimeout
and check for changes indocument.styleSheets
setTimeout
并检查document.styleSheets
更改setTimeout
and check for changes in the styling of a specific element you create but style with the new CSSsetTimeout
并检查您创建的特定元素的样式是否更改,但使用新CSS样式
5th option is too crazy and assumes you have control over the content of the CSS, so forget it. Plus it checks for current styles in a timeout meaning it will flush the reflow queue and can be potentially slow. The slower the CSS to arrive, the more reflows. So, really, forget it.
第5个选项太疯狂了,它假定您可以控制CSS的内容,所以就算了。 另外,它还会检查超时中的当前样式,这意味着它将刷新重排队列,并且可能会变慢。 CSS到达的速度越慢,重排就越多。 所以,真的,算了吧。
So how about implementing the magic?
那么如何实施魔术呢?
// MAGIC
// #1
link.onload = function () {
CSSDone('onload listener');
}
// #2
if (link.addEventListener) {
link.addEventListener('load', function() {
CSSDone("DOM's load event");
}, false);
}
// #3
link.onreadystatechange = function() {
var state = link.readyState;
if (state === 'loaded' || state === 'complete') {
link.onreadystatechange = null;
CSSDone("onreadystatechange");
}
};
// #4
var cssnum = document.styleSheets.length;
var ti = setInterval(function() {
if (document.styleSheets.length > cssnum) {
// needs more work when you load a bunch of CSS files quickly
// e.g. loop from cssnum to the new length, looking
// for the document.styleSheets[n].href === url
// ...
// FF changes the length prematurely :()
CSSDone('listening to styleSheets.length change');
clearInterval(ti);
}
}, 10);
// MAGIC ends
测试 (Test)
Test page - riiiight here. I'm loading a CSS file delayed two seconds on the server. Attaching all those event listeners and timeouts above. Adding another timeout that just says "... and two seconds later ... " after (you guessed it!) two seconds. Now observing los resultados...
测试页面-在这里。 我在服务器上加载了延迟两秒钟CSS文件。 附加以上所有这些事件侦听器和超时。 在(您猜对了!)两秒钟之后添加另一个超时,该超时仅显示“ ...和两秒钟后...”。 现在观察los resultados ...
结果 (Results)
IE fires
readystatechange
andload
(tested years ago, too lazy to test now again). Now with IE9 maybeaddEventListener
will work too?IE会触发
readystatechange
和load
(几年前测试过,太懒了以至于无法再次测试)。 现在使用IE9,也许addEventListener
也可以工作吗?Firefox (like before) fires nothing. It updates the
length
ofdocument.styleSheets
immediately, not waiting for the file to actually arrive. So the outcome in my test log is:Firefox(如之前)不会触发任何操作。 它会立即更新
document.styleSheets
的length
,而不必等待文件实际到达。 所以我的测试日志中的结果是:zOMG, CSS #1 is done: listening to styleSheets.length change ... and two seconds later ...
Opera fires
load
viaonload
and viaaddEventListener
too. Like FF it also incrementsdocument.styleSheets.length
immédiatement. The outcome:Opera也通过
onload
和addEventListener
触发load
。 像FF也增加document.styleSheets.length
immédiatement。 结果:zOMG, CSS #1 is done: listening to styleSheets.length change ... and two seconds later ... zOMG, CSS #1 is done: onload listener zOMG, CSS #1 is done: DOM's load event
Chrome and Safari will not fire events but will update
document.styleSheets
only when the file arrives, yey!Chrome和Safari不会触发事件,但只会在文件到达时更新
document.styleSheets
,是的!... and two seconds later ... zOMG, CSS #1 is done: listening to styleSheets.length change
All in all, there's at least one way to tell when the stylesheet is loaded in each browser, except Firefox. Now that's embarrassing.
总而言之,除了Firefox之外,至少有一种方法可以确定何时在每个浏览器中加载样式表。 现在太尴尬了。
Firefox真的没有希望吗? (Is there really no hope for Firefox?)
If you go really crazy than yes - implement magic #5 but it has serious drawbacks.
如果您真的比真正的疯了,那就实施第5点魔术法,但它有严重的弊端。
Otherwise the object
trick should do - all browsers seem to fire load
and/or readystatechange
event consistently. Obviously it's a little more complicated. Although probably not as complicated as monitoring the document.styleSheets
collection
否则, object
技巧应该readystatechange
-所有浏览器似乎始终触发load
和/或readystatechange
事件。 显然,这要复杂一些。 尽管可能没有监视document.styleSheets
集合那么复杂
I also tried MozAfterPaint - it might work but didn't for me, because my CSS didn't change anything on the page that required repaint. Obviously not a fit-all solution.
我还尝试了MozAfterPaint-它可能有效,但不适用于我,因为我CSS并未更改需要重绘的页面上的任何内容。 显然不是万能的解决方案。
Another thing that failed was checking document.styleSheets[n].cssRules
. Although document.styleSheets.length
is updated immediately, I was thinking FF cannot update document.styleSheets[n].cssRules
(document.styleSheets[n].sheet.cssRules
) until the CSS actually arrives. However since FF 3.5 (or thereabouts) you don't have access to cssRules
collection when the file is hosted on a different domain (CDN say). Security thing, you see. Even cssRules.length
would've been enough, but nah.
失败的另一件事是检查document.styleSheets[ n ].cssRules
。 尽管document.styleSheets.length
立即更新,但我认为FF在CSS实际到来之前无法更新document.styleSheets[ n ].cssRules
( document.styleSheets[ n ].sheet.cssRules
)。 但是,从FF 3.5(或cssRules
当文件托管在其他域上时,您将无权访问cssRules
集合(例如CDN)。 您知道安全性。 甚至cssRules.length
就足够了,但是不。
外卖 (Takeaways)
- Any ideas about a clever (or not so clever) workaround that lets us figure out when CSS is loaded in FF? Please comment. 关于聪明(或不太聪明)的变通办法的任何想法都可以让我们弄清楚何时在FF中加载CSS? 请评论。
Libraries can benefit from
document.styleSheets.length
trick to support Chrome and Safari. I know at least that YUI3 doesn't support callbacks onY.Get.css()
in Safari (nor FF)库可以从
document.styleSheets.length
技巧中受益,以支持Chrome和Safari。 我至少知道Y.Get.css()
不支持Safari(也不是FF)中Y.Get.css()
上的回调Firefox 4 must implement
load
on stylesheets 🙂 No doubt about it. IMO all browsers should fireload
on everything related to external resources.Firefox 4必须在样式表上实现
load
🙂毫无疑问。 IMO所有浏览器都应在与外部资源相关的所有内容上触发load
。
更新:FF解决了! (UPDATE: FF solved!)
Thanks to Ryan's comment below, Zach and Oleg, turns out there is something that works. And that is:
多亏了Ryan在下面的评论Zach和Oleg ,才发现有一些可行的方法。 那就是:
you create a
style
element, not alink
您创建
style
元素,而不是link
add
@import "URL"
添加
@import "URL"
poll for access to that style node's
cssRules
collection轮询访问该样式节点的
cssRules
集合
It just happens so that Firefox will not populate this collection until the file arrives!
发生这种情况是为了使Firefox在文件到达之前不会填充此集合!
var style = document.createElement('style');
style.textContent = '@import "' + url + '"';
var fi = setInterval(function() {
try {
style.sheet.cssRules; // <--- MAGIC: only populated when file is loaded
CSSDone('listening to @import-ed cssRules');
clearInterval(fi);
} catch (e){}
}, 10);
head.appendChild(style);
Updated my test and seems to work just fine.
更新了我的测试,看来一切正常。
Whew!
ew!
I still maintain that this is unnecessarily complex and all browsers should simply fire load
event. Seems to me this FF behavior might change at any time, as well as Safari's not populating document.styleSheet
我仍然认为这不必要地复杂,所有浏览器都应该简单地触发load
事件。 在我看来,这种FF行为可能随时更改,以及Safari不会填充document.styleSheet
One thing to note: this access to cssRules
is not a failure of the same security check that doesn't allow cssRules
access with outside domains. In this case we're accessing cssRules
of the inline style
and that's fine. We still cant access the styles of the @import-ed file from a different domain.
需要注意的一件事:对cssRules
访问并不是同一安全检查的失败,该安全检查不允许cssRules
访问外部域。 在这种情况下,我们将访问内联style
cssRules
,这很好。 我们仍然无法从其他域访问@ import-ed文件的样式。
Side note: makes me wonder - this could be a technique to preload JS without executing too 🙂
旁注:让我纳闷-这可能是一种无需执行太早就预加载JS的技术🙂
Tell your friends about this post on Facebook and Twitter
在Facebook和Twitter上告诉您的朋友有关此帖子的信息
翻译自: https://www.phpied.com/when-is-a-stylesheet-really-loaded/
qt 加载样式表