Обработка <? Xml-stylesheet> похожа на <link rel = "stylesheet">?

Во время исследования преимуществ и недостатков присоединения CSS с <?xml-stylesheet> Обрабатывая инструкцию, я столкнулся с некоторыми проблемами.

Предположим, у нас есть простой документ XHTML (который поставляется с application/xhtml+xml Тип MIME и просмотр в веб-браузере):

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>A sample XHTML document</title>
    <script type="application/javascript" src="/script.js"></script>
  </head>
  <body>
    <h1>A heading</h1>
  </body>
</html>

Тогда у нас есть внешний файл CSS (пусть он будет назван style.css и положить в корневой каталог):

h1 { color: red; }

Во-первых, в script.js, Я динамически присоединяю этот CSS с link элемент:

const link = document.createElement('link');
Object.entries({rel: 'stylesheet', type: 'text/css', href: '/style.css'})
      .forEach(([name, value]) => link.setAttribute(name, value));
document.head.appendChild(link);

Затем сценарий ожидает, пока таблица стилей не завершит загрузку и не достигнет ее. sheet имущество:

link.addEventListener('load', function() {
  const stylesheet = link.sheet;
});

После этого скрипт может манипулировать этой таблицей стилей, например:

stylesheet.cssRules.item(0).style.color = 'green';      // modify an existing rule
stylesheet.insertRule('body { background: #ffc; }', 1); // insert a new rule

Но сейчас я не могу понять, возможны ли такие же манипуляции, если таблица стилей прикреплена к <?xml-stylesheet> инструкция по обработке:

const pi = document.createProcessingInstruction('xml-stylesheet',
           'href="/style.css" type="text/css"');
document.insertBefore(pi, document.documentElement);

Во-первых, ИП, похоже, не имеет load событие, поэтому сценарий не может знать, когда таблица стилей готова. Во-вторых, нет ничего подобного sheet собственности, поэтому вы не можете позвонить pi.sheet чтобы достичь таблицы стилей.

Есть ли способ преодолеть эти трудности и перейти от сценария к таблице стилей, связанной с <?xml-stylesheet> ЧИСЛО ПИ?

1 ответ

Во-первых, кажется, что в PI нет события загрузки, поэтому сценарий не может знать, когда таблица стилей готова.

Ты можешь использовать PerformanceObserver проверить запрошенные и загруженные ресурсы. Итерирует узлы document, проверить .nodeType7 или же .nodeType8, как ProcessingInstruction узел может иметь comment.nodeType, Получить "resource" свойство из записей производительности. парсить .nodeValue отфильтрованного узла для URL в href="URL"проверьте, равно ли значение "resource" ввода производительности, затем проверьте, если .styleSheet.href значение равно проанализированному URL, а если проанализированный URL равен записи производительности "resource" стоимость имущества. Если trueитерация .cssRules или же .rules из styleSheet загружен в ProcessingInstruction узел.

window.onload = () => {
  let resource;
  const observer = new PerformanceObserver((list, obj) => {
    for (let entry of list.getEntries()) {
      for (let [key, prop] of Object.entries(entry.toJSON())) {
        if (key === "name") {
          resource = prop;
          var nodes = document.childNodes;
          _nodes: for (let node of nodes) {
            if (node.nodeType === 7 || node.nodeType === 8 
            && node.nodeValue === pi.nodeValue) {
              let url = node.baseURI 
                        + node.nodeValue.match(/[^href="][a-z0-9/.]+/i)[0];
              if (url === resource) {
                observer.disconnect();
                // use `setTimeout` here for
                // low RAM, busy CPU, many processes running
                let stylesheets = node.rootNode.styleSheets;
                for (let xmlstyle of stylesheets) {
                  if (xmlstyle.href === url && url === resource) {
                    let rules = (xmlstyle["cssRules"] || xmlstyle["rules"]);
                    for (let rule of rules) {
                      // do stuff
                      console.log(rule, rule.cssText, rule.style, xmlstyle);
                      break _nodes;
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  });

  observer.observe({
    entryTypes: ["resource"]
  });

  const pi = document.createProcessingInstruction('xml-stylesheet',
    'href="style.css" type="text/css"');
  document.insertBefore(pi, document.documentElement);

}

plnkr http://plnkr.co/edit/uXfSzu0dMDCOfZbsdA7n?p=preview

Вы также можете использовать MutationObserver, setTimeout() обрабатывать

недостаточно оперативной памяти, загружен процессор, запущено много процессов

window.onload = function() {
  let observer = new MutationObserver(function(mutations) {
    console.log(mutations)
    for (let mutation of mutations) {
      for (let node of mutation.addedNodes) {
        if (node.nodeName === "xml-stylesheet") {
          let url = node.baseURI 
                    + node.nodeValue.match(/[^href="][a-z0-9/.]+/i)[0];
          setTimeout(function() {
            for (let style of document.styleSheets) {
              if (style.href === url) {
                observer.disconnect();
                // do stuff
                console.log(style)
              }
            }
          // adjust `duration` to compensate for device
          // low RAM, busy CPU, many processes running
          }, 500)  
        }
      }
    }
  });

  observer.observe(document, {
    childList: true
  });

  const pi = document.createProcessingInstruction('xml-stylesheet',
    'href="style.css" type="text/css"');
  document.insertBefore(pi, document.documentElement);

}

plnkr http://plnkr.co/edit/AI4QZiBUx6f1Kmc5qNG9?p=preview


В качестве альтернативы используйте XMLHttpRequest() или же fetch() запросить .css файл, создать и добавить <style> элемент к document, делать вещи с текстом ответа, установить .textContent из style элемент для корректировки css текст.

Другие вопросы по тегам