【问题标题】:How get all computed css properties of element and its children in Javascript如何在Javascript中获取元素及其子元素的所有计算css属性
【发布时间】:2018-12-04 12:29:11
【问题描述】:

我正在尝试使用 pdfKit 在 python 中设置服务,以从 html 文件创建 pdf 文件。

所以基本上我会将我的元素作为字符串发送并期望服务器返回它的 pdf 版本,但为了准确表示我还需要发送元素的 css 文件。

我该怎么做?生成仅包含元素及其所有子元素的相关样式属性和选择器的 JSON / 对象。尊重层次结构,没有重复。有类似的问题,但它们已经过时并且往往不考虑儿童元素。

我在想也许有一种方法可以从这个元素创建一个新的 DOM,然后获取根 css?

【问题讨论】:

  • 你看过window.getComputedStyledeveloper.mozilla.org/en-US/docs/Web/API/Window/…吗?它返回一个对象,其中所有 CSS 属性都应用于一个元素。
  • @elveti 当然可以,但是如何在尊重等级制度的同时获得所有儿童的风格
  • @Mojimi 计算的样式确实尊重层次结构
  • 在此处查看最佳答案 Original (ES 2017):stackoverflow.com/questions/19784064/… 但 AFAIK 它不适用于儿童样式。我认为您必须为每个孩子再次运行该函数
  • 创建一个循环,停止条件将是您在要获取 css 属性的最后一个子项中定义的“id”。

标签: javascript css wkhtmltopdf python-pdfkit


【解决方案1】:

这是我想出来的,基本上传递你想要提取样式的元素及其子元素,它会将样式表作为字符串返回给你。在运行 sn -p 之前打开您的控制台,您将看到来自 console.log 的输出。

因为我想支持提取每个元素,即使是那些没有选择器的元素,我不得不用专门为它们生成的唯一 uuid 替换每个元素 id,以方便您的输出样式。这种方法的问题在于,如果您使用 id 进行样式设置或用户交互,则在调用 extractCSS 后,您将在相关元素上失去此类功能。

但是,一旦您的pdfKit 进程完成生成,使用我传递的oldId 更改回来是非常简单的。只需通过函数返回的elements 调用swapBackIds。如果您在我的 sn-p 中取消注释调用,您可以看到行为的不同:#root 粉红色背景将消失,因为样式针对元素 id

总而言之,您需要:

  1. 使用您要提取的元素调用extractCSS
  2. 使用res.stylesheet 生成您的pdf
  3. 致电swapBackIdsres.elements

// Generate an unique id for your element
// From https://stackoverflow.com/a/2117523/2054072
function uuidv4 () {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
    return v.toString(16);
  });
}

// Flatten an array
// https://stackoverflow.com/a/15030117/2054072
function flatten(arr) {
  return arr.reduce(function (flat, toFlatten) {
    return flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten);
  }, []);
}

function recursiveExtract (element) {
  var id = uuidv4()
  var oldId = element.id

  var computed = window.getComputedStyle(element)
  var style = computed.cssText

  // Now that we get the style, we can swap the id
  element.setAttribute('id', id)

  // The children are not a real array but a NodeList, we need to convert them
  // so we can map over them easily
  var children = Array.prototype.slice.call(element.children)
  return [{ id: id, style: style, oldId: oldId }].concat(children.map(recursiveExtract))
}

function extractCSS (element) {
  if (!element) { return { elements: [], stylesheet: '' } }

  var raw = recursiveExtract(element)
  var flat = flatten(raw)
  
  return {
    elements: flat,
    stylesheet: flat.reduce(function (acc, cur) {
      var style = '#' + cur.id + ' {\n' + cur.style + '\n}\n\n'
      return acc + style
    }, '')
  }
}

var pdfElement = document.querySelector('#root')
var res = extractCSS(pdfElement)

console.log(res.stylesheet)

function swapBackIds (elements) {
  elements.forEach(function (e) {
    var element = document.getElementById(e.id)
    element.setAttribute('id', e.oldId)
  })
}

swapBackIds(res.elements)
#root {
  background-color: pink;
}

.style-from-class {
  background-color: red;
  width: 200px;
  height: 200px;
}

.style-from-id {
  background-color: green;
  width: 100px;
  height: 100px;
}
<div id="root">
  <span>normal</span>
  <span style="background: blue">inline</span>
  <div class="style-from-class">
    style-class
  </div>
  <div class="style-from-id">
    style-id
    <div style="font-size: 10px">a very nested</div>
    <div style="font-size: 12px; color: white">and another</div>
  </div>
</div>

<div id="ignored-sibling">
</div>

【讨论】:

  • @Mojimi 对这种方法有什么顾虑吗?
  • @AshishRanjan 不要进行此类编辑,它们是不必要的。
  • 它们不是不必要的 IMO,它是为了提高代码质量。 #1 - 分号使用不一致,#2 - var -> const, let。你的答案,你的规则:)
  • 这 5 个半数仅用于从其他地方获取的部分代码,您可以删除这些代码,但是是的,我很惊讶当时我还没有使用 const 跨度>
【解决方案2】:

	
let para = document.querySelector('p');
let compStyles = window.getComputedStyle(para);
para.textContent = 'My computed font-size is ' + compStyles.getPropertyValue('font-size') + ',\nand my computed background is ' +  compStyles.getPropertyValue('background') + '.';
p {
  width: 400px;
  margin: 0 auto;
  padding: 20px;
  font: 2rem/2 sans-serif;
  text-align: center;
  background: purple;
  color: white;
}
&lt;p&gt;Hello&lt;/p&gt;

您可以使用getComputedStyle 方法获取样式属性的计算值

【讨论】:

    猜你喜欢
    • 2021-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-13
    • 2012-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多