1

Is it possible to read the class values of the style's part from script part in vue?

e.g I have:

.node-output02 {
    bottom: #{-2+$portSize/-2}px;
    left: #{$nodeWidth/3}px;
  }

in script I want to do:

const left = .node-output02.left
  • Welcome to SO. Could you please share the code that you have tried or found in your research so far? – palaѕн Feb 20 '20 at 12:52
  • Does this answer your question? [How do you read CSS rule values with JavaScript?](https://stackoverflow.com/questions/324486/how-do-you-read-css-rule-values-with-javascript) – Mr. Polywhirl Feb 20 '20 at 12:57
  • This is a bit of a backwards approach. Set the style with Vue to begin with, and then you won't need to access it from the CSS later because you'll already have the values. – Dan Feb 20 '20 at 13:19
  • The solution provided by Mr. Polywhirl is amazing. Thank you guys! – Over Drive Gain Feb 21 '20 at 17:58

1 Answers1

0

This is less of a Vue issue and more of a general JS issue.

Using this code (for obtaining the CSS text from a stylesheet), you can parse the CSS into a query-able object.

It's not fool-proof, but it's a start.

console.log('left =', getStyleObject('.node-output02')['left']); // 420px

function getStyleText(className) {
  let classes = document.styleSheets[0].rules || document.styleSheets[0].cssRules,
      styleText = '';
  Array.from(classes).forEach(clazz => {
    if (clazz.selectorText == className) {
      styleText += clazz.cssText || clazz.style.cssText;
    }
  });
  return styleText;
}

function getStyleObject(className) {
  let styleText = getStyleText(className);
  if (styleText.length > 0) {
    let leftBraceIndex = styleText.indexOf('{'),
        rightBraceIndex = styleText.lastIndexOf('}'),
        selector = styleText.substring(0, leftBraceIndex).trim(),
        ruleText = styleText.substring(leftBraceIndex + 1, rightBraceIndex).trim();
    return Object.fromEntries(ruleText.split(/\s*;\s*/g)
      .filter(v => v.length > 0) // filter out empty (if there is a trailing semi-colon)
      .map(v => v.split(/\s*:\s*/g)));
  }
  return null;
}
.node-output02 {
  bottom: 360px;
  left: 420px;
}

Multiple style rules...

In the example below, everything is merged top-to-bottom, but !important is ignored, a reducer might be a better option.

console.log('left =', getStyleObject('.node-output02')['left']); // 100%;

function getStyleText(className) {
  let classes = document.styleSheets[0].rules || document.styleSheets[0].cssRules,
      styles = [];
  Array.from(classes).forEach(clazz => {
    if (clazz.selectorText == className) {
      let styleText = clazz.cssText || clazz.style.cssText,
          leftBraceIndex = styleText.indexOf('{'),
          rightBraceIndex = styleText.lastIndexOf('}'),
          selector = styleText.substring(0, leftBraceIndex).trim(),
          ruleText = styleText.substring(leftBraceIndex + 1, rightBraceIndex).trim();
      styles.push(ruleText);
    }
  });
  return styles;
}

function getStyleObject(className) {
  return Object.assign.apply({}, getStyleText(className).map(ruleText => {
    return Object.fromEntries(ruleText.split(/\s*;\s*/g)
      .filter(v => v.length > 0)
      .map(v => v.split(/\s*:\s*/g)));
  }));
}
.node-output02 {
  bottom: 360px;
  left: 420px;
}

.node-output02 {
  left: 5em !important; /* This should precedence... */
}

.node-output02 {
  left: 100%; /* This will be the returned value. */
}

Reducer

If you want to maintain precedence, you can identify !important exceptions.

Again, this is not fool-proof, because selector specificity is not maintained either. But it is more robust than the code above.

console.log('left =', getStyleObject('.node-output02')['left']); // 5em

function getStyleText(className) {
  let classes = document.styleSheets[0].rules || document.styleSheets[0].cssRules,
      styles = [];
  Array.from(classes).forEach(clazz => {
    if (clazz.selectorText == className) {
      let styleText = clazz.cssText || clazz.style.cssText,
          leftBraceIndex = styleText.indexOf('{'),
          rightBraceIndex = styleText.lastIndexOf('}'),
          selector = styleText.substring(0, leftBraceIndex).trim(),
          ruleText = styleText.substring(leftBraceIndex + 1, rightBraceIndex).trim();
      styles.push(ruleText);
    }
  });
  return styles;
}

function getStyleObject(className) {
  return cleanupValues(getStyleText(className).reduce((result, ruleText) => {
    let css = parseRuleText(ruleText);
    for (let [prop, value] of Object.entries(css)) {
      if (result.hasOwnProperty(prop) &&
          result[prop].includes('!important') &&
          !value.includes('!important')) {
        continue; // ignore...
      }
      result[prop] = value;
    }
    return result;
  }, {}));
}

function parseRuleText(ruleText) {
  return Object.fromEntries(ruleText.split(/\s*;\s*/g)
    .filter(v => v.length > 0)
    .map(v => v.split(/\s*:\s*/g)));
}

function cleanupValues(css) {
  for (let [prop, value] of Object.entries(css)) {
    if (value.includes('!important')) {
      css[prop] = value.replace(/\s*!important/, '');
    }
  }
  return css;
}
.node-output02 {
  bottom: 360px;
  left: 420px;
}

.node-output02 {
  left: 5em !important; /* This will be the returned value. */
}

.node-output02 {
  left: 100%; /* Not as important as the preceeding rule. */
}
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132