【问题标题】:Trigger dynamic loading of css触发css的动态加载
【发布时间】:2023-02-23 02:04:25
【问题描述】:

我的 javascript 应用程序有时会添加一个可选的 css 文件,其中包含:

var head = document.getElementsByTagName('head')[0];
var style = document.createElement('link');
style.href = "fonts.css";
style.type = 'text/css';
style.rel = 'stylesheet';
head.append(style);

我以为添加的 css 中定义的样式会立即应用,但它们没有。

我的问题是我需要在实际应用这些样式时执行一个函数。我如何检测它发生的时刻?

【问题讨论】:

  • 那么资源必须加载首先。您可能会向正在创建的链接元素添加一个 load 处理程序以等待它,但不确定它是否完全匹配“当这些风格被实际应用时”,因为解析文件也可能需要一些时间。

标签: css


【解决方案1】:

我认为您无法检测到何时应用了样式。您能做的最好的事情就是检测何时加载了新文件。您可以在 link 元素上使用 onload 事件来执行代码。确保您定义了事件处理程序设置 href 属性 - 我以前被这个抓住过。

【讨论】:

    【解决方案2】:

    有几种方法可能有效,第一种是使用最明显的事件侦听器选择来侦听在创建的元素上触发的 load 事件,如下所示(代码中带有解释性 cmet):

    // caching the document in a variable with a shorter name (because I'm lazy, and
    // don't like typing unnecessarily):
    const doc = document,
      // a simple function to create and append an element, taking four
      // arguments:
      // what: String, the element-type you wish to create,
      // where: String, a CSS selector to find the element to which the created-
      //        element should be appended,
      // fn: function, the callback function to fire once the element is loaded,
      // props: Object, properties and property-values to apply to the created-
      //        element, with a default value of an empty Object literal:
      appendElementTo = (what, where, fn, props = {}) => {
        // using document.createElement() to create the desired element,
        // passing that created-element along with the props Object to
        // Object.assign() to add the given properties (if any)
        let creation = Object.assign(doc.createElement(what), props),
          // using document.querySelector() to retrieve the element to which
          // the created-element should be appended; this will return the first
          // matching element from the document (if such an element exists), or
          // null (if not matching element exists):
          target = doc.querySelector(where);
    
        // here we check that the target element exists, and use a Yoda condtion to
        // check that the target.nodeType is 1 (and is therefore an HTMLElement),
        // I use the Yoda condition because it's almost impossible to accidentally
        // use an assignment in place of a comparison:
        if (target && 1 === target.nodeType) {
          // if there is a callback function supplied:
          if (fn) {
            // we use EventTarget.addEventListener() to bind the callback function
            // aas the 'load' event-listener on the created-element:
            creation.addEventListener('load', fn);
          }
    
          // we use Element.append() to append the created-element to the
          // target element:
          target.append(creation);
        }
        // this function returns nothing to the calling context, you may wish to
        // add an explicit return in your use-case (but that's beyond the scope
        // of the current question).
      },
      // a simple function to demonstrate the callback working (this can be more
      // or less complex as you require to achieve your desired functionality):
      test = (evt) => {
        document.querySelector('body p:last-child').style.color = `red`
      };
    
    // calling the function, passing in the Strings
    // 'link' and 'head' (the 'what' and 'where' arguments respectively):
    appendElementTo('link', 'head',
      // passing in a reference to the callback function (note the
      // deliberate lack of parentheses):
      test,
      // and, finally, an Object literal for the properties to apply to the created element:
      {
        // the element-property as the Object keys, and the element property-values
        // as the Object values (the search paramater and calls to Math.random() are to cause
        // the browser to load the resource on every run, rather than caching (in your own
        // use-case this may not be required, adjust to taste):
        href: `https://davidrhysthomas.co.uk/linked/base.css?v=${Math.random()}.${Math.random()}`,
        type: `text/css`,
        rel: `stylesheet`,
      });
    <main>
      <h2>Demo content</h2>
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusamus repellendus, eos itaque ab doloremque dolorum reiciendis ut, unde commodi. Esse, voluptatem dolorem sint ratione placeat quas, inventore non autem ullam aperiam quae minima eaque nobis
        eos. Voluptatum sunt perspiciatis ab illum tempora quam, odio voluptatem ipsam eaque amet, cumque animi aut, facilis quidem nihil quasi, vel rerum quaerat numquam vero deserunt earum ipsum. Voluptatem atque, quas provident. Voluptatum, expedita consequatur
        modi voluptate reiciendis, consequuntur nostrum laboriosam itaque suscipit magni dolorem maxime cumque unde facere, culpa animi, corporis nam necessitatibus? Nesciunt impedit aliquam molestias quos, consequatur, neque ad architecto quibusdam laborum
        optio dolores!</p>
      <p>Provident, voluptatum. Optio ut officiis nam ex debitis officia animi placeat dolorum inventore ipsa sapiente illum numquam doloremque assumenda libero a impedit laboriosam, ratione eveniet expedita, voluptates nihil est, perspiciatis. Nostrum magnam
        possimus fugiat dolor, quod repellat beatae porro? Delectus eaque minima facilis autem temporibus fugiat numquam impedit nisi aspernatur cupiditate reiciendis corporis, placeat totam, ipsa, commodi aut. Quam porro ratione dolor sunt est dicta sapiente
        molestiae adipisci eveniet dolorum assumenda pariatur deserunt vitae officiis, rem nostrum in recusandae doloremque repellat odit voluptatum, aperiam necessitatibus. Quia consectetur quod doloribus esse, tempore iusto, vel culpa ut, consequatur quas
        odit.
      </p>
    </main>

    JS Fiddle

    或者,这可能有点麻烦,您可以使用 CSS 动画,并在 JavaScript 中监听 transitionend 事件:

    // the linked CSS defines a keyframes animation on the <body> element, here we
    // use EventTarget.addEventListener() to bind the anonymous function as the
    // event-handler for the 'animationend' event (the event fired once the animation
    // has ended):
    document.body.addEventListener('animationend', (e) => {
        // the functionality to be fired on completion of the animation, which - as the
      // animation is defined in the linked CSS stylesheet - should only run once the
      // stylesheet has loaded into the document and been applied:
      console.log("animation ended");
    // in JS Fiddle this wasn't necessary, but here in SO the function kept getting called
    // despite the animation-iteration-count being explicitly set to 1 (so the animation
    // should have run only once). It is, however, a cheap guard against a memory leak; so
    // here we use the options to cause the function to run only once:
    }, {once:true});
    
    const doc = document,
      appendElementTo = (what, where, props = {}) => {
        let creation = Object.assign(doc.createElement(what), props),
          target = doc.querySelector(where);
        if (target && 1 === target.nodeType) {
          target.append(creation);
        }
      };
    
    appendElementTo('link', 'head', {
      href: `https://davidrhysthomas.co.uk/linked/base2.css?v=${Math.random()}.${Math.random()}`,
      type: `text/css`,
      rel: `stylesheet`,
    });
    /*
    
    The content from the linked stylesheet, commented out to prevent this CSS being applied:
    
    // defining the animation, specifying only the completion (this was the simplest do-nothing
    // CSS I could think of):
    @keyframes loadVerification {
      to {
        color: currentColor;
      }
    }
    
    :root {
      --spacing: 0.5rem;
    }
    
    *,::before,::after {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }
    
    html,body {
      min-block-size: 100%;
    }
    
    body {
      // only two parts matter; the animation defined above and the call to use that
      // animation:
      animation: loadVerification 0.1ms;
      font-family: system-ui;
      font-size: 16px;
      font-weight: 400;
      padding-block: var(--spacing);
    }
    
    main {
      background-image: radial-gradient(circle at 0 0, hsl(150deg 90% 70% / 0), hsl(150deg 90% 70% / 0.6));
      block-size: 100%;
      border: 1px solid currentColor;
      inline-size: clamp(20rem, 80%, 1200px);
      margin-inline: auto;
      padding: var(--spacing);
    }
    
    p {
      margin-block: var(--spacing);
    }
    
    */
    <link href="https://davidrhysthomas.co.uk/linked/base.css" rel="stylesheet" type="text/css">
    <main>
      <h2>Demo content</h2>
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusamus repellendus, eos itaque ab doloremque dolorum reiciendis ut, unde commodi. Esse, voluptatem dolorem sint ratione placeat quas, inventore non autem ullam aperiam quae minima eaque nobis
        eos. Voluptatum sunt perspiciatis ab illum tempora quam, odio voluptatem ipsam eaque amet, cumque animi aut, facilis quidem nihil quasi, vel rerum quaerat numquam vero deserunt earum ipsum. Voluptatem atque, quas provident. Voluptatum, expedita consequatur
        modi voluptate reiciendis, consequuntur nostrum laboriosam itaque suscipit magni dolorem maxime cumque unde facere, culpa animi, corporis nam necessitatibus? Nesciunt impedit aliquam molestias quos, consequatur, neque ad architecto quibusdam laborum
        optio dolores!</p>
      <p>Provident, voluptatum. Optio ut officiis nam ex debitis officia animi placeat dolorum inventore ipsa sapiente illum numquam doloremque assumenda libero a impedit laboriosam, ratione eveniet expedita, voluptates nihil est, perspiciatis. Nostrum magnam
        possimus fugiat dolor, quod repellat beatae porro? Delectus eaque minima facilis autem temporibus fugiat numquam impedit nisi aspernatur cupiditate reiciendis corporis, placeat totam, ipsa, commodi aut. Quam porro ratione dolor sunt est dicta sapiente
        molestiae adipisci eveniet dolorum assumenda pariatur deserunt vitae officiis, rem nostrum in recusandae doloremque repellat odit voluptatum, aperiam necessitatibus. Quia consectetur quod doloribus esse, tempore iusto, vel culpa ut, consequatur quas
        odit.</p>
    </main>

    JS Fiddle demo

    【讨论】:

      【解决方案3】:

      您必须将 onload 事件添加到链接:

      style.onload = myFunction;
      

      在 myFunction 中,您必须等待文档准备就绪,即(jQuery 代码):

      function myFunction() {
        $(document).ready(
          function() {
            // do what you need to
          }
        );
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-04-14
        • 2020-04-24
        • 2018-02-16
        • 1970-01-01
        • 2023-03-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多