我正在尝试将事件处理程序附加到链接标记的load事件,以在样式表加载后执行某些代码。
new_element = document.createElement('link');
new_element.type = 'text/css';
new_element.rel = 'stylesheet';
new_element.href = 'http://domain.tld/file.css';
new_element.addEventListener('load', function() { alert('foo'); }, false);
document.getElementsByTagName('head')[0].appendChild(new_element)
我也尝试过onreadystatechange
new_element.onreadystatechange = function() { alert('foo'); }
不幸的是,这两种方法都没有导致触发警报。 此外,在使用addEventListener注册'load'事件的处理程序后,new_element.onload为null。这是正常的吗?
感谢, 安德鲁
ps:我可能不会使用任何框架来解决这个问题
答案 0 :(得分:52)
在我看来,对于使用IMG标记及其onerror事件的此问题,这是一个更好的解决方案。这个方法可以完成工作而不需要循环,进行扭曲的样式遵守,或者在iframe中加载文件等。这个解决方案在文件加载时正确激活,如果文件已经被缓存,则立即激活(这比大多数DOM的讽刺性更好)加载事件处理缓存资产)。这是我博客上的一篇文章,解释了方法 - Back Alley Coder post - 我厌倦了没有合法的解决方案,享受!
var loadCSS = function(url, callback){
var link = document.createElement('link');
link.type = 'text/css';
link.rel = 'stylesheet';
link.href = url;
document.getElementsByTagName('head')[0].appendChild(link);
var img = document.createElement('img');
img.onerror = function(){
if(callback) callback(link);
}
img.src = url;
}
答案 1 :(得分:10)
对于CSS样式表(一般不是LINK元素)我使用手动间隔,通过戳它的规则长度。它适用于crossbrowser(AFAIT)。
try {
if ( cssStylesheet.sheet && cssStylesheet.sheet.cssRules.length > 0 )
cssLoaded = 1;
else if ( cssStylesheet.styleSheet && cssStylesheet.styleSheet.cssText.length > 0 )
cssLoaded = 1;
else if ( cssStylesheet.innerHTML && cssStylesheet.innerHTML.length > 0 )
cssLoaded = 1;
}
catch(ex){}
在上面的代码中,cssStylesheet是DOMElement。
答案 2 :(得分:4)
即使您添加内联:
<link rel="stylesheet" type="text/css" href="foo.css" onload="alert('xxx')"/>
它不会在FireFox中触发onload
link
个{{1}}元素事件。 (它将在IE中工作)
答案 3 :(得分:3)
所有信用都归于托比亚斯上面所说的,但这里的内容略有扩展:
function _cssIsLoaded(cssStylesheet) {
var cssLoaded = 0;
try {
if ( cssStylesheet.sheet && cssStylesheet.sheet.cssRules.length > 0 )
cssLoaded = 1;
else if ( cssStylesheet.styleSheet && cssStylesheet.styleSheet.cssText.length > 0 )
cssLoaded = 1;
else if ( cssStylesheet.innerHTML && cssStylesheet.innerHTML.length > 0 )
cssLoaded = 1;
}
catch(ex){ }
if(cssLoaded) {
// your css is loaded! Do work!
// I'd recommend having listeners subscribe to cssLoaded event,
// and then here you can emit the event (ie. EventManager.emit('cssLoaded');
} else {
// I'm using underscore library, but setTimeout would work too
// You basically just need to call the function again in say, 50 ms
_.delay(_.bind(this._cssIsLoaded, this), 50, cssStylesheet);
}
}
你用类似的东西(使用jquery)来调用它:
var link = $("<link>");
link.attr({
type: 'text/css',
rel: 'stylesheet',
href: sheet
});
$("head").append(link);
// link.get(0), because you want the actual element, not jQuery-wrapped element
self._cssIsLoaded(link.get(0));
答案 4 :(得分:3)
link.innerHTML,link.styleSheet和cssRules都是很好的方法,但它们不适用于属于原始域之外的域的样式表(因此跨站点样式表加载失败)。当使用子域与域(例如www)或使用静态CNS时,这可能是非常意外的。而且它很烦人,因为元素没有同源限制。
这是一个解决方案,它为支持它的浏览器(IE和Opera)使用onload方法,但是对不支持的浏览器使用定时间隔,并比较ownerNode和owningElement节点,以检查样式表何时制作它进入DOM的方式。
http://www.yearofmoo.com/2011/03/cross-browser-stylesheet-preloading.html
答案 5 :(得分:2)
var CSSload = function(link, callback) {
var cssLoaded = false;
try{
if ( link.sheet && link.sheet.cssRules.length > 0 ){
cssLoaded = true;
}else if ( link.styleSheet && link.styleSheet.cssText.length > 0 ){
cssLoaded = true;
}else if ( link.innerHTML && link.innerHTML.length > 0 ){
cssLoaded = true;
}
}
catch(ex){ }
if ( cssLoaded ){
callback();
}else{
setTimeout(function(){
CSSload(link);
}, 100);
}
};
用法:
var $link = $('<link rel="stylesheet" media="screen" href="file.css"/>');
$('head').append($link);
CSSload($link.get(0), function(){
// do something onLoad
});
答案 6 :(得分:1)
此功能适用于所有浏览器以及跨域和相同域的情况,也可以处理javascripts和样式表的注入。
function loadScript(src, type, callback_fn) {
var loaded = false, scrpt, img;
if(type === 'script') {
scrpt = document.createElement('script');
scrpt.setAttribute('type', 'text/javascript')
scrpt.setAttribute('src', src);
} else if(type === 'css') {
scrpt = document.createElement('link')
scrpt.setAttribute('rel', 'stylesheet')
scrpt.setAttribute('type', 'text/css')
scrpt.setAttribute('href', src);
}
document.getElementsByTagName('head')[0].appendChild(scrpt);
scrpt.onreadystatechange = function(){
if (this.readyState === 'complete' || this.readyState === 'loaded') {
if(loaded === false) {
callback_fn();
}
loaded = true;
}
};
scrpt.onload = function() {
if(loaded === false) {
callback_fn();
}
loaded = true;
};
img = document.createElement('img');
img.onerror = function(){
if(loaded === false) {
callback_fn();
}
loaded = true;
}
img.src = src;
};
答案 7 :(得分:0)
E.g。 Android浏览器不支持元素的“onload”/“onreadystatechange”事件:http://pieisgood.org/test/script-link-events/
但它返回:
"onload" in link === true
所以,我的解决方案是从userAgent检测Android浏览器,然后在样式表中等待一些特殊的css规则(例如,重置“body”边距)。
如果它不是Android浏览器并且它支持“onload”事件 - 我们将使用它:
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();
}
答案 8 :(得分:0)
这个方法更适合我。
// Create a <link> and set it in an HTML node
const
$link = document.createElement("link");
$link.setAttribute('rel', 'stylesheet');
$link.setAttribute('href', '/build/style/test.css');
document.head.appendChild($link);
// Event about load
onloadCSS($link).then(function(url) {
console.log('CSS loaded: ' + url);
}).catch(function(e) {
console.log('Failed to load CSS');
});
function onloadCSS($link){
return new Promise(function(resolve, reject) {
const
options = {
headers: ({'Accept': 'text/css,*/*;q=0.1'})
},
url = $link.getAttribute('href');
fetch(url, options).then(function(response) {
if(response.status === 200){
return resolve(url);
}
return reject({status: response.status});
}).catch(function(e) {
return reject(e);
});
});
}
答案 9 :(得分:-4)
当页面本身加载时,href没有你需要应用你的东西的加载事件。
window.onload = function(){
//code here
}
使用此页面上的功能:http://www.dustindiaz.com/top-ten-javascript/
添加事件的body元素(在行中)