web-dev-qa-db-fra.com

Comment obtenir toutes les propriétés css calculées de l'élément et de ses enfants en Javascript

J'essaie de configurer un service en python en utilisant pdfKit pour créer un fichier pdf à partir de fichiers html.

Donc, fondamentalement, j'enverrai mon élément sous forme de chaîne et je m'attendrai à ce que le serveur retourne une version pdf de celle-ci, mais pour être une représentation précise, je dois également envoyer un fichier CSS de l'élément.

Comment puis-je faire ceci? Générez JSON/object avec uniquement les propriétés de style et les sélecteurs d’un élément et de tous ses enfants. Respecter la hiérarchie et pas de doublons. Il existe des questions similaires, mais elles sont dépassées et ont tendance à ne pas prendre en compte les éléments enfants.

Je pensais qu'il y avait peut-être un moyen de créer un nouveau DOM à partir de cet élément, puis d'obtenir le css racine?

14
Mojimi

Voici quelque chose que je suis venu avec, passe essentiellement l'élément que vous souhaitez extraire les styles et ceux de ses enfants, et il vous retournera la feuille de style sous la forme d'une chaîne. Ouvrez votre console avant d'exécuter l'extrait et vous verrez le résultat du console.log.

Parce que je voulais supporter l'extraction de chaque élément, même ceux sans sélecteur, je devais remplacer chaque identifiant d'élément par un uuid unique généré spécifiquement pour eux afin de faciliter le style de votre sortie. Le problème avec cette approche est que si vous utilisez des identifiants pour le style ou pour l’interaction de l’utilisateur, vous allez perdre cette fonctionnalité sur les éléments concernés après avoir appelé extractCSS.

Cependant, il est assez simple d’utiliser la variable oldId que je passe pour changer une fois que votre processus pdfKit a terminé la génération. Appelez simplement swapBackIds en passant la elements renvoyée par la fonction. Vous pouvez voir la différence de comportement si vous supprimez la mise en commentaire de l'appel dans mon extrait: le fond rose #root disparaîtrait car le style cible un élément id.

Dans l'ensemble, vous devez:

  1. Appelez extractCSS avec l'élément que vous voulez extraire
  2. Générez votre pdf en utilisant res.stylesheet
  3. Appelez swapBackIds avec res.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>

3
Balthazar

	
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;
}
<p>Hello</p>

vous pouvez utiliser la méthode getComputedStyle pour obtenir la valeur calculée de la propriété de style

0
Navin Gelot