有没有听一下<link>
元素的onload事件?
F.ex:
var link = document.createElement('link');
link.rel = 'stylesheet';
link.href = 'styles.css';
link.onload = link.onreadystatechange = function(e) {
console.log(e);
};
这适用于<script>
个元素,但不适用于<link>
。还有另外一种方法吗?
我只需要知道外部样式表中的样式何时应用于DOM。
更新
注入隐藏的<iframe>
是一个想法,将<link>
添加到头部并在iframe中监听window.onload
事件?它应该在加载css时触发,但它可能无法保证它被加载到顶部窗口......
答案 0 :(得分:16)
今天,所有现代浏览器都支持链接标记上的onload事件。所以我会防范黑客攻击,比如创建一个img元素并设置onerror:
if !('onload' in document.createElement('link')) {
imgTag = document.createElement(img);
imgTag.onerror = function() {};
imgTag.src = ...;
}
这应该为FF-8以及早期和旧的Safari&amp; amp;提供解决方法。 Chrome版本。
次要更新:
正如迈克尔所指出的那样,有一些浏览器例外,我们总是希望应用黑客攻击。在Coffeescript中:
isSafari5: ->
!!navigator.userAgent.match(' Safari/') &&
!navigator.userAgent.match(' Chrom') &&
!!navigator.userAgent.match(' Version/5.')
# Webkit: 535.23 and above supports onload on link tags.
isWebkitNoOnloadSupport: ->
[supportedMajor, supportedMinor] = [535, 23]
if (match = navigator.userAgent.match(/\ AppleWebKit\/(\d+)\.(\d+)/))
match.shift()
[major, minor] = [+match[0], +match[1]]
major < supportedMajor || major == supportedMajor && minor < supportedMinor
答案 1 :(得分:7)
这是一种破解,但是如果你可以编辑CSS,你可以添加一个特殊的样式(没有可见的效果),你可以使用这篇文章中的技术来监听:http://www.west-wind.com/weblog/posts/478985.aspx
您需要页面中具有CSS将影响的类或ID的元素。当您的代码检测到其样式已更改时,CSS已加载。
黑客,正如我所说:)
答案 2 :(得分:3)
我在Chrome上执行此操作的方式(未在其他浏览器上测试)是使用Image
对象加载CSS并捕获其onerror
事件。问题是浏览器不知道这个资源是否是图像,所以无论如何它都会尝试获取它。但是,由于它不是实际图像,因此会触发onerror
个处理程序。
var css = new Image();
css.onerror = function() {
// method body
}
// Set the url of the CSS. In link case, link.href
// This will make the browser try to fetch the resource.
css.src = url_of_the_css;
请注意,如果资源已被提取,则此提取请求将到达缓存。
答案 3 :(得分:2)
E.g。 Android浏览器不支持&#34; onload&#34; /&#34; onreadystatechange&#34;元素事件:http://pieisgood.org/test/script-link-events/
但它返回:
"onload" in link === true
因此,我的解决方案是从userAgent检测Android浏览器,然后在样式表中等待一些特殊的css规则(例如,重置为&#34; body&#34; margin)。
如果它不是Android浏览器,它支持&#34; onload&#34;事件 - 我们将使用它:
var userAgent = navigator.userAgent,
iChromeBrowser = /CriOS|Chrome/.test(userAgent),
isAndroidBrowser = /Mozilla\/5.0/.test(userAgent) && /Android/.test(userAgent) && /AppleWebKit/.test(userAgent) && !iChromeBrowser;
addCssLink('PATH/NAME.css', function(){
console.log('css is loaded');
});
function addCssLink(href, onload) {
var css = document.createElement("link");
css.setAttribute("rel", "stylesheet");
css.setAttribute("type", "text/css");
css.setAttribute("href", href);
document.head.appendChild(css);
if (onload) {
if (isAndroidBrowser || !("onload" in css)) {
waitForCss({
success: onload
});
} else {
css.onload = onload;
}
}
}
// We will check for css reset for "body" element- if success-> than css is loaded
function waitForCss(params) {
var maxWaitTime = 1000,
stepTime = 50,
alreadyWaitedTime = 0;
function nextStep() {
var startTime = +new Date(),
endTime;
setTimeout(function () {
endTime = +new Date();
alreadyWaitedTime += (endTime - startTime);
if (alreadyWaitedTime >= maxWaitTime) {
params.fail && params.fail();
} else {
// check for style- if no- revoke timer
if (window.getComputedStyle(document.body).marginTop === '0px') {
params.success();
} else {
nextStep();
}
}
}, stepTime);
}
nextStep();
}
答案 4 :(得分:1)
既然你不喜欢我的黑客攻击:)我四处寻找其他方式并发现one by brothercake。
基本上,建议使用AJAX来使浏览器对其进行缓存,然后将链接加载视为瞬时,因为CSS已缓存。这可能不会每次都有效(例如,某些浏览器可能会关闭缓存),但几乎总是如此。
答案 5 :(得分:1)
另一种方法是检查加载的样式表的数量。例如:
使用“css_filename”css文件的url或文件名,并在加载css时“回调”回调函数:
var style_sheets_count=document.styleSheets.length;
var css = document.createElement('link');
css.setAttribute('rel', 'stylesheet');
css.setAttribute('type', 'text/css');
css.setAttribute('href', css_filename);
document.getElementsByTagName('head').item(0).appendChild(css);
include_javascript_wait_for_css(style_sheets_count, callback, new Date().getTime());
function include_javascript_wait_for_css(style_sheets_count, callback, starttime)
/* Wait some time for a style sheet to load. If the time expires or we succeed
* in loading it, call a callback function.
* Enter: style_sheet_count: the original number of style sheets in the
* document. If this changes, we think we finished
* loading the style sheet.
* callback: a function to call when we finish loading.
* starttime: epoch when we started. Used for a timeout. 12/7/11-DWM */
{
var timeout = 10000; // 10 seconds
if (document.styleSheets.length!=style_sheets_count || (new Date().getTime())-starttime>timeout)
callback();
else
window.setTimeout(function(){include_javascript_wait_for_css(style_sheets_count, callback, starttime)}, 50);
}
答案 6 :(得分:0)
您需要一个您知道的样式的特定元素,或者如果您控制CSS文件,您可以为此目的插入一个虚拟元素。当css文件的内容应用于DOM时,此代码将完全使您的回调运行。
// dummy element in the html
<div id="cssloaded"></div>
// dummy element in the css
#cssloaded { height:1px; }
// event handler function
function cssOnload(id, callback) {
setTimeout(function listener(){
var el = document.getElementById(id),
comp = el.currentStyle || getComputedStyle(el, null);
if ( comp.height === "1px" )
callback();
else
setTimeout(listener, 50);
}, 50)
}
// attach an onload handler
cssOnload("cssloaded", function(){
alert("ok");
});
如果您在文档底部使用此代码,则可以将 el 和 comp 变量移出计时器之外,以便获取元素一次。但是如果你想在文档中的某个地方(比如头部)附加处理程序,你应该按原样保留代码。
注意:在FF 3 +,IE 5.5 +,Chrome
上测试答案 7 :(得分:0)
这个技巧来自xLazyLoader jQuery plugin:
var count = 0;
(function(){
try {
link.sheet.cssRules;
} catch (e) {
if(count++ < 100)
cssTimeout = setTimeout(arguments.callee, 20);
else
console.log('load failed (FF)');
return;
};
if(link.sheet.cssRules && link.sheet.cssRules.length == 0) // fail in chrome?
console.log('load failed (Webkit)');
else
console.log('loaded');
})();
在FF(3.6.3)和Chrome(linux - 6.0.408.1 dev)
中进行本地测试和工作演示here(请注意,这不适用于跨站点css加载,如在演示中,在FF下完成)
答案 8 :(得分:0)
xLazyLoader插件失败,因为对于属于其他域的样式表隐藏了cssRules属性(中断了相同的源策略)。所以你要做的就是比较ownerNode和owningElements。
以下是对待办事项的详尽解释: http://yearofmoo.com/2011/03/cross-browser-stylesheet-preloading/
答案 9 :(得分:0)
// this work in IE 10, 11 and Safari/Chrome/Firefox/Edge
// if you want to use Promise in an non-es6 browser, add an ES6 poly-fill (or rewrite to use a callback)
let fetchStyle = function(url) {
return new Promise((resolve, reject) => {
let link = document.createElement('link');
link.type = 'text/css';
link.rel = 'stylesheet';
link.onload = resolve;
link.href = url;
let headScript = document.querySelector('script');
headScript.parentNode.insertBefore(link, headScript);
});
};
答案 10 :(得分:0)
这是跨浏览器的解决方案
// Your css loader
var d = document,
css = d.head.appendChild(d.createElement('link'))
css.rel = 'stylesheet';
css.type = 'text/css';
css.href = "https://unpkg.com/tachyons@4.10.0/css/tachyons.css"
// Add this
if (typeof s.onload != 'undefined') s.onload = myFun;
} else {
var img = d.createElement("img");
img.onerror = function() {
myFun();
d.body.removeChild(img);
}
d.body.appendChild(img);
img.src = src;
}
function myFun() {
/* ..... PUT YOUR CODE HERE ..... */
}
答案基于this link,其内容为:
幕后发生的事情是浏览器尝试加载 img 元素中的CSS,并且因为样式表不是 图像中, img 元素引发 onerror 事件并执行 功能。值得庆幸的是,浏览器在加载整个CSS文件之前 确定其不是图像并触发 onerror 事件。
在现代浏览器中,您可以执行css.onload并将该代码添加为后备版本,以覆盖2011年以前的旧浏览器,当时只有Opera和Internet Explorer分别支持onload事件和onreadystatechange 。< / p>
注意:我也回答了here,这是我的副本,应为我的诚实而受到惩罚:P