【问题标题】:Handling <?xml-stylesheet> similar to <link rel="stylesheet">?处理 <?xml-stylesheet> 类似于 <link rel="stylesheet">?
【发布时间】:2017-05-20 17:15:05
【问题描述】:

在研究使用&lt;?xml-stylesheet&gt;处理指令附加CSS的优缺点时,我遇到了一些问题。

假设我们有一个简单的 XHTML 文档(以application/xhtml+xml MIME 类型交付并在 Web 浏览器中查看):

<!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 中,我使用link 元素动态附加此CSS:

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

但是现在,我不知道如果样式表附加了&lt;?xml-stylesheet&gt; 处理指令,是否可以进行相同的操作:

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

首先,PI 似乎没有load 事件,因此脚本无法知道样式表何时准备就绪。其次,没有像sheet 这样的属性,所以你不能调用pi.sheet 来访问样式表。

有什么办法可以克服这些困难,从脚本到与&lt;?xml-stylesheet&gt;PI 关联的样式表?

【问题讨论】:

  • 你想用加工指令达到什么目的?
  • @guest271314,我正在调查使用&lt;?xml-stylesheet&gt; 附加样式表的优缺点。
  • “这个对象没有任何事件,也没有任何属性来获取它的样式表。” 不确定问题是什么?您是否尝试获取并解析在xhtml document 中加载的StyleSheet?您能否包括xhtml document 和您尝试过的内容,并在问题中描述要求?
  • 实际上,我认为您根本无法使用处理器指令“做”任何事情。如果您需要对样式表的加载进行那种级别的控制,请使用 。另一方面,如果您只需要知道所有样式表何时完成加载,您可以使用window.onload...
  • @MrLister,我的脚本动态插入了&lt;!xml-stylesheet&gt;,在window.onload 被触发很久之后。

标签: javascript css xhtml processing-instruction cssom


【解决方案1】:

首先,PI似乎没有加载事件,所以脚本不知道什么时候 样式表已准备就绪。

您可以使用PerformanceObserver 检查请求和加载的资源。迭代document的节点,检查.nodeType7.nodeType8,因为ProcessingInstruction节点可能有comment.nodeType。从性能条目中获取"resource" 属性。为href="URL"处的URL解析过滤节点的.nodeValue,检查值是否等于性能条目的"resource",然后检查.styleSheet.href的值是否等于解析的URL,以及解析的URL是否等于性能条目"resource" 属性值。如果是true,则迭代在ProcessingInstruction 节点加载的styleSheet 中的.cssRules.rules

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);

}

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

也可以使用MutationObserversetTimeout()来处理

内存不足,CPU 繁忙,运行许多进程

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);

}

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


或者,使用XMLHttpRequest()fetch() 请求.css 文件,创建&lt;style&gt; 元素并将其附加到document,对响应文本进行处理,将.textContentstyle 元素设置为调整@ 987654355@文字。

【讨论】:

  • 不幸的是,PerformanceObserver 只能判断资源(例如style.css)何时加载,即浏览器引擎何时接收到它的所有字节。但它无法判断新样式表何时真正添加到 document.styleSheets 列表中,并且其属性如 cssRules 可用于脚本。
  • 在功能强大的设备上,没有问题。观察者“捕获”了一个加载的 CSS 文件,它被添加到列表中的速度非常快,以至于近期调用 document.styleSheets 会返回带有新样式表的已更新列表。但是在功能低的设备上测试代码(低内存,繁忙的 CPU,许多进程正在运行),我发现样式表没有及时调用document.styleSheets。此调用返回旧样式表列表,并且在其中找不到请求的样式表。仅在更新一两秒 document.styleSheets 后。
  • 我认为真正的解决方案可能是直接观察document.styleSheets 并在添加新样式表时捕获事件。但是我不知道该怎么做(除了使用setInterval)。
  • @HydrochoerusHydrochaeris "但是在功能低的设备上测试代码(低内存、繁忙的 CPU、许多进程正在运行),我发现样式表没有及时调用文档.styleSheets" 您可以在PerformanceObserverMutationObserver 方法中使用setTimeout()。调整durationsetTimeout 以补偿特定设备。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-25
  • 1970-01-01
  • 2015-01-14
  • 1970-01-01
  • 2013-08-29
  • 2011-09-08
  • 1970-01-01
相关资源
最近更新 更多