获取计算样式并省略默认值

Get the computed style and omit defaults

本文关键字:默认值 计算 样式 获取      更新时间:2023-09-26

我正在尝试获取元素的当前运行时样式并过滤掉具有默认值的属性。例如,使用如下标记:

<style>
    .foo { background: red }
    span { font-size:30px }
</style>

<div style="color: blue">
    <span id="bar" class="foo">hello</span>
</div>

我希望结果是:

 background-color: red;
 color: blue;
 font-size: 30px;

我尝试了window.getComputedStyle,但它返回了很多东西,我不确定如何过滤掉默认值。任何指示将不胜感激。

你去,我通过添加新的虚拟 DOM 元素来做到这一点,以了解哪些样式是任何元素的默认样式。

/**
 * IE does not have `getComputedStyle` 
 */
window.getComputedStyle = window.getComputedStyle || function( element ) {
  return element.currentStyle;
}
/**
 * get computed style for an element, excluding any default styles
 *
 * @param {DOM} element
 * @return {object} difference
 */
function getStylesWithoutDefaults( element ) {
  // creating an empty dummy object to compare with
  var dummy = document.createElement( 'element-' + ( new Date().getTime() ) );
  document.body.appendChild( dummy );
  // getting computed styles for both elements
  var defaultStyles = getComputedStyle( dummy );
  var elementStyles = getComputedStyle( element );
  // calculating the difference
  var diff = {};
  for( var key in elementStyles ) {
    if(elementStyles.hasOwnProperty(key)
          && defaultStyles[ key ] !== elementStyles[ key ] )
    {
      diff[ key ] = elementStyles[ key ];
    }
  }
  // clear dom
  dummy.remove();
  return diff;
}

/**
 * usage
 */
console.log( getStylesWithoutDefaults( document.getElementById( 'bar' ) ) );

笔记:

  • 结果将具有一些额外的属性,而不仅仅是您提到的属性。

演示 - 应打开控制台

这是一个更强大的解决方案,使用 iframe .此解决方案一次对多个元素效率低下,在这种情况下,您需要使用片段来批量插入元素并传入标记名称数组。

var getDefaultStyling = function(tagName){
    if(!tagName) tagName = "dummy-tag-name";
    //  Create dummy iframe
    var iframe = document.createElement("iframe");
    document.body.appendChild(iframe);
    //  Create element within the iframe's document
    var iframeDocument = iframe.contentDocument;
    var targetElement = iframeDocument.createElement(tagName);
    iframeDocument.body.appendChild(targetElement);
    //  Grab styling (CSSStyleDeclaration is live, and all values become "" after element removal)
    var styling = iframe.contentWindow.getComputedStyle(targetElement);
    var clonedStyling = {};
    for(var i = 0, len = styling.length; i < len; i++){
        var property = styling[i];
        clonedStyling[i] = property;
        clonedStyling[property] = styling[property];
    }
    //  Remove iframe
    document.body.removeChild(iframe);
    //  Return cloned styling
    return clonedStyling;
};
var getUniqueUserStyling = function(element){
    var allStyling = window.getComputedStyle(element);
    var defaultStyling = getDefaultStyling(element.tagName);
    var userStyling = {};
    for(var i = 0, len = allStyling.length; i < len; i++){
        var property = allStyling[i];
        var value = allStyling[property];
        var defaultValue = defaultStyling[property];
        if(value != defaultValue){
            userStyling[property] = value;
        }
    }
    return userStyling;
};

用法:getUniqueUserStyling(myElement)

我已经根据 mattsven 的回答构建了一个我认为更现代、更完整、更高效的解决方案。

您所要做的就是调用 getUserStyles 方法,将节点作为参数,如下所示: Styles.getUserStyles(document.querySelector('#bar'))

显然,此代码段并未考虑较旧的浏览器支持,因此如果要在公共网站上使用它,则应进行一些调整。

class Styles {
    // Returns a dummy iframe with no styles or content
    // This allows us to get default styles from the browser for an element
    static getStylesIframe() {
        if (typeof window.blankIframe != 'undefined') {
            return window.blankIframe;
        }
        window.blankIframe = document.createElement('iframe');
        document.body.appendChild(window.blankIframe);
        return window.blankIframe;
    }
    // Turns a CSSStyleDeclaration into a regular object, as all values become "" after a node is removed
    static getStylesObject(node, parentWindow) {
        const styles = parentWindow.getComputedStyle(node);
        let stylesObject = {};
        for (let i = 0; i < styles.length; i++) {
            const property = styles[i];
            stylesObject[property] = styles[property];
        }
        return stylesObject;
    }
    // Returns a styles object with the browser's default styles for the provided node
    static getDefaultStyles(node) {
        const iframe = Styles.getStylesIframe();
        const iframeDocument = iframe.contentDocument;
        const targetElement = iframeDocument.createElement(node.tagName);
        iframeDocument.body.appendChild(targetElement);
        const defaultStyles = Styles.getStylesObject(targetElement, iframe.contentWindow);
        targetElement.remove();
        return defaultStyles;
    }
    // Returns a styles object with only the styles applied by the user's CSS that differ from the browser's default styles
    static getUserStyles(node) {
        const defaultStyles = Styles.getDefaultStyles(node);
        const styles = Styles.getStylesObject(node, window);
        let userStyles = {};
        for (let property in defaultStyles) {
            if (styles[property] != defaultStyles[property]) {
                userStyles[property] = styles[property];
            }
        }
        return userStyles;
    }
};

如果你之后需要使用getPropertyValue,这里有一个选项,就像这里一样

var computedStyles = getComputedStyles(document.body);
var propertyValue = computedStyles.getPropertyValue("prop-name");

使用此函数:

function getDefaultComputedStyles(el)
{
    var temp = document.createElement("div");
    document.body.appendChild(temp);
    var defaultStyles = getComputedStyle(temp);
    var extraStyles = getComputedStyle(el);
    var foundStyles = [];
    for(var i=0; i<defaultStyles.length; i++)
    {
        var extraStyleIndex = extraStyles[i];
        var extraStyleValue = extraStyles.getPropertyValue(extraStyles[i]);
        if(defaultStyles.getPropertyValue(defaultStyles[i]) !== extraStyleValue)
        {
          foundStyles.push(JSON.parse(`{"${extraStyleIndex}":"${extraStyleValue}"}`));
        }
    }
    foundStyles.getPropertyValue = function(ind){
        var result = this.filter(el => (`${ind}` in el));
        return result[0]!=undefined ? result[0][Object.keys(result[0])] : null;
    }
    return foundStyles;
}

试试这个大小:

  1. 把它们放在某个地方。

    <textarea id="t1"> </textarea> <textarea id="t2"> </textarea> <textarea id="t3"> </textarea> <textarea id="t4"> </textarea>

  2. 下一个

function test() {
    let arr = [];
    let elem = _("right-Sidebar");
    let cStyl = window.getComputedStyle(elem);
    let txt1;
    for (x of cStyl) { txt1 += x + "=" + cStyl[x] + "'n"; }
    _("t1").value = txt1;
    let ss = document.getElementsByTagName("Style");
    const sstext = ss[0].innerHTML;
    ss[0].innerHTML = "";
    let elem2 = _("right-Sidebar");
    let cStyl2 = window.getComputedStyle(elem2);
    let txt2;
    for (x2 of cStyl2) { txt2 += x2 + "=" + cStyl2[x2] + "'n"; }
    _("t2").value = txt2;
    let div = _el(elem.tagName);
    let dfrag = new DocumentFragment();
    dfrag.appendChild(div);
    document.body.appendChild(dfrag);
    let cStyl3 = window.getComputedStyle(div);
    let txt3;
    for (x3 of cStyl3) { txt3 += x3 + "=" + cStyl3[x3] + "'n"; }
    _("t3").value = txt3;
    alert(_("t3").value === _("t2").value);

    let val1 = _("t2").value.split("'n");
    let val2 = _("t1").value.split("'n");

    let i = 0;
    while (i < val1.length) {
        if (val1[i] !== val2[i]) {
            arr.push(val1[i] + "'n" + val2[i] + "'n'n'n");
        }
        i++;
    }
    _("t4").value = "";
    _("t4").value = arr.join("'n");
}

这里是..使用纯javscript..我只将jquery添加到小提琴中以设置document.ready事件。

这是代码:

$(document).ready(function () {
    var div = document.getElementById('output');
    var x = document.getElementById('frame').contentWindow.document.createElement('x');
    document.getElementById('frame').contentWindow.document.body.appendChild(x);
    var defautlStyles = window.getComputedStyle(x);
    var barStyles = window.getComputedStyle(document.getElementById('bar'));
    for (i = 0; i < defautlStyles.length; i++) {
        if (defautlStyles["" + defautlStyles[i]] != barStyles["" + barStyles[i]]) {
            var p = document.createElement('p');
            p.innerText += barStyles[i] + ": " + barStyles["" + barStyles[i]];
            div.appendChild(p);
        }
    }
});

我使用 iframe 向其添加元素,因此添加元素的样式不会受到文档默认样式的影响。这是小提琴

希望对你有帮助...

您可以使用,例如:

window.getComputedStyle(document.getElementById('bar'))

这将返回一个对象,其中包含具有id 'bar' 的元素的所有计算样式。

因此,例如,您可以执行以下操作:

var styles = window.getComputedStyle(document.getElementById('bar'));
styles = "background-color:" + styles['background-color'] + ";color:" + styles['color'] + ";font-size:" + styles['font-size'] + ";";
console.log(styles);

请注意,颜色值将以 RGBA 格式返回。

演示小提琴