【问题标题】:Dynamically loading css file using javascript with callback without jQuery使用带有回调的javascript动态加载css文件而不使用jQuery
【发布时间】:2011-07-29 02:24:40
【问题描述】:

我正在尝试使用 javascript 动态加载 css 文件,并且不能使用任何其他 js 库(例如 jQuery)。

css 文件加载,但我似乎无法获得回调来为它工作。下面是我正在使用的代码

var callbackFunc = function(){
    console.log('file loaded');     
};
var head = document.getElementsByTagName( "head" )[0];
var fileref=document.createElement("link");
    fileref.setAttribute("rel", "stylesheet");
    fileref.setAttribute("type", "text/css");
    fileref.setAttribute("href", url);

    fileref.onload  = callbackFunc;
    head.insertBefore( fileref, head.firstChild );

使用以下代码添加脚本标签以加载 js 文件有效并触发回调:

var callbackFunc = function(){
    console.log('file loaded');     
};

var script = document.createElement("script");

script.setAttribute("src",url);
script.setAttribute("type","text/javascript");

script.onload  = callbackFunc ;

head.insertBefore( script, head.firstChild );

我在这里做错了吗?任何其他可以帮助我实现这一目标的方法将不胜感激?

【问题讨论】:

  • 我建议如果有你不想想要使用的库,那么不要在问题中标记它们。标记它们仍然会为您的问题吸引 [错误] 类型的开发人员。
  • stackoverflow.com/questions/3078584/link-element-onload 非常相似。是否使用 jQuery 无关紧要(jQuery 代码可以很容易地转换为 vanilla)。主要问题是,直到最近,WebKit 还不支持 link 元素的 load 事件。这是大量且仍然非常普遍的手机,包括 iOS 和 Android。 (不寻常的是,IE 支持自 IE7 以来的事件,如果不是更早的话。)

标签: javascript css callback loading


【解决方案1】:

不幸的是,大多数现代浏览器都没有对样式表的 onload 支持。我通过谷歌搜索找到了一个解决方案。

引用自: http://thudjs.tumblr.com/post/637855087/stylesheet-onload-or-lack-thereof

基础知识

这个最基本的实现可以在区区 30 行——独立于框架——JavaScript 代码中完成:

function loadStyleSheet( path, fn, scope ) {
   var head = document.getElementsByTagName( 'head' )[0], // reference to document.head for appending/ removing link nodes
       link = document.createElement( 'link' );           // create the link node
   link.setAttribute( 'href', path );
   link.setAttribute( 'rel', 'stylesheet' );
   link.setAttribute( 'type', 'text/css' );

   var sheet, cssRules;
// get the correct properties to check for depending on the browser
   if ( 'sheet' in link ) {
      sheet = 'sheet'; cssRules = 'cssRules';
   }
   else {
      sheet = 'styleSheet'; cssRules = 'rules';
   }

   var interval_id = setInterval( function() {                     // start checking whether the style sheet has successfully loaded
          try {
             if ( link[sheet] && link[sheet][cssRules].length ) { // SUCCESS! our style sheet has loaded
                clearInterval( interval_id );                      // clear the counters
                clearTimeout( timeout_id );
                fn.call( scope || window, true, link );           // fire the callback with success == true
             }
          } catch( e ) {} finally {}
       }, 10 ),                                                   // how often to check if the stylesheet is loaded
       timeout_id = setTimeout( function() {       // start counting down till fail
          clearInterval( interval_id );             // clear the counters
          clearTimeout( timeout_id );
          head.removeChild( link );                // since the style sheet didn't load, remove the link node from the DOM
          fn.call( scope || window, false, link ); // fire the callback with success == false
       }, 15000 );                                 // how long to wait before failing

   head.appendChild( link );  // insert the link node into the DOM and start loading the style sheet

   return link; // return the link node;
}

这将允许您使用这样的 onload 回调函数加载样式表:

loadStyleSheet( '/path/to/my/stylesheet.css', function( success, link ) {
   if ( success ) {
      // code to execute if the style sheet was loaded successfully
   }
   else {
      // code to execute if the style sheet failed to successfully
   }
} );

或者如果你想让你的回调保持它的范围/上下文,你可以做这样的事情:

loadStyleSheet( '/path/to/my/stylesheet.css', this.onComplete, this );

【讨论】:

  • 这将导致 IE7 或更高版本自动停止脚本。所以不会触发回调。
  • 谢谢,我还遇到了另一篇建议相同的博文here。基本上是使用计时器来检查头部的所有脚本,看看是否加载了所需的脚本。
  • 当我尝试执行它时,它总是返回 false,尽管样式表加载得很好。在调试时我发现link[sheet] 总是返回null。你有什么想法吗
  • 非常有帮助,解决了我只在 Safari 浏览器中遇到的问题。
  • 他页面上的选项 #2 似乎是一个更好的解决方案:“使用 AJAX 加载样式表的内容,创建样式节点并将 XHR responseText 插入样式节点。”
【解决方案2】:

这种原版 JS 方法适用于所有现代浏览器:

let loadStyle = function(url) {
  return new Promise((resolve, reject) => {
    let link    = document.createElement('link');
    link.type   = 'text/css';
    link.rel    = 'stylesheet';
    link.onload = () => { resolve(); console.log('style has loaded'); };
    link.href   = url;

    let headScript = document.querySelector('script');
    headScript.parentNode.insertBefore(link, headScript);
  });
};

// works in IE 10, 11 and Safari/Chrome/Firefox/Edge
// add an ES6 polyfill for the Promise (or rewrite to use a callback)

【讨论】:

  • 完美运行,ES6 与我的 Angular 打字稿应用程序配合得很好!
  • 在发布问题时无法在 iOS、Android、Chrome 或 Safari 中运行,即使使用 ES6 Polyfill,并且仍然无法在未修补最新系统(例如很多用户手机)- WebKit 仅在最近添加了对 link 元素上的 load 事件的支持。
【解决方案3】:

前段时间我为此做了一个库,叫做Dysel,希望对你有帮助

示例: https://jsfiddle.net/sunrising/qk0ybtnb/

var googleFont = 'https://fonts.googleapis.com/css?family=Lobster';
var jquery = 'https://code.jquery.com/jquery.js';
var bootstrapCss = 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css';
var bootstrapJs = 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js';
var smokeCss = 'https://rawgit.com/alfredobarron/smoke/master/dist/css/smoke.min.css';
var smokeJs = 'https://rawgit.com/alfredobarron/smoke/master/dist/js/smoke.min.js';

// push links into an array in the correct order
var extRes = [];
extRes.push(googleFont);
extRes.push(bootstrapCss);
extRes.push(smokeCss);
extRes.push(jquery);
extRes.push(bootstrapJs);
extRes.push(smokeJs);

// let this happen
dysel({
  links: extRes,
  callback: function() {
    alert('everything is now loaded, this is awesome!');
  }, // optional
  nocache: false, // optional
  debug: false // optional
});

【讨论】:

  • 太棒了,另一个库添加到我的“必须”中;)谢谢
【解决方案4】:

您可以在 html 文件中创建一个空的 css 链接并为该链接指定一个 ID。例如

<link id="stylesheet_css" rel="stylesheet" type="text/css" href="css/dummy.css?"/>

然后用 ID 名称调用它并更改 'href' 属性

【讨论】:

  • 我无权访问该页面的 html。我只能编辑第 3 方 html 页面正在加载的 javascript。所以解决方案需要基于javascript。不过谢谢你的想法。
【解决方案5】:

yepnope.js 可以加载 CSS 并在完成时运行回调。例如

yepnope([{
  load: "styles.css",
  complete: function() {
    console.log("oooooo. shiny!");
  }
}]);

【讨论】:

  • 它在插入链接元素时运行回调。
【解决方案6】:

我们是这样做的。通过使用“requestAnimationFrame”(如果没有用,则回退到简单的“加载”事件)。

顺便说一句,这是 Google 在其“页面速度”手册中推荐的方式: https://developers.google.com/speed/docs/insights/OptimizeCSSDelivery

<script>
    function LoadCssFile(cssPath) {
        var l = document.createElement('link'); l.rel = 'stylesheet'; l.href = cssPath;
        var h = document.getElementsByTagName('head')[0]; h.parentNode.insertBefore(l, h);
    }
    var cb = function() {
        LoadCssFile('file1.css');
        LoadCssFile('file2.css');
    };
    var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
    if (raf) raf(cb);
    else window.addEventListener('load', cb);
</script>

【讨论】:

  • 如果我理解答案,它与所要求的内容无关。它在加载 PAGE 时加载 CSS 文件。问题是如何在加载 CSS 文件时调用函数。
【解决方案7】:

旧问题的新答案:

您可以简单地使用 AJAX 请求 CSS 文件的文本并将其放在 &lt;style&gt; 标记中。将样式附加到 DOM 后,它们立即可用。

这是我想出的一个脚本:

/**
 * Given a URL for a JS or CSS file, this function will
 * load the asset and return a Promise which will reject
 * on error or resolve when the asset is loaded.
 */
function loadAsset(url){
  return new Promise(async (resolve, reject)=>{
    var asset;
    if(url.trim().substr(-3).toLowerCase() === '.js'){
      asset = document.createElement('script');
      asset.addEventListener('load', resolve);
      asset.addEventListener('error', reject);
      document.head.appendChild(asset);
      asset.setAttribute('src', url);
    }else{
      var styles = await fetch(url)
        .then(c=>c.text())
        .catch(reject);
      asset = document.createElement('style');
      asset.appendChild(document.createTextNode(styles));
      document.head.appendChild(asset);
      resolve();
    }
  });
}

【讨论】:

    猜你喜欢
    • 2013-08-20
    • 2011-01-07
    • 1970-01-01
    • 1970-01-01
    • 2017-04-10
    • 1970-01-01
    • 1970-01-01
    • 2010-10-29
    • 1970-01-01
    相关资源
    最近更新 更多