0

您好,我一直在尝试使用 PostCSS,并且正在努力编写一个插件,该插件在找到某些 CSS 属性时会附加一条新规则。

我正在努力实现的目标……</p>

启动 CSS:

.selector {
    color: red;
    not-yet-standard-property-a: 10px;
    not-yet-standard-property-b: 20px;
}

PostCSS 插件后:

.selector {
    color: red;
    not-yet-standard-property-a: 10px;
    not-yet-standard-property-b: 20px;
}

.ie .selector {
    standard-property-a: 10px;
    standard-property-b: 20px;
}

每当我看到其中一个规则时,我都可以轻松添加新规则not-yet-standard-property-*……</p>

return function (css) {
    css.walkRules(function (rule) {
        rule.walkDecls('not-yet-standard-property-a', function (decl) {
            css.insertAfter(rule, '.ie ' + rule.selector + '{ standard-property-a: '+ decl.value +' }');
        });
        rule.walkDecls('not-yet-standard-property-b', function (decl) {
            css.insertAfter(rule, '.ie ' + rule.selector + '{ standard-property-b: '+ decl.value +' }');
        });
        rule.walkDecls('not-yet-standard-property-c', function (decl) {
            css.insertAfter(rule, '.ie ' + rule.selector + '{ standard-property-c: '+ decl.value +' }');
        });
    });
}

但是输出并不理想……</p>

.selector {
    color: red;
    not-yet-standard-property-a: 10px;
    not-yet-standard-property-b: 20px;
    not-yet-standard-property-c: 53px;
}
.ie .selector {
    standard-property-c: 53px;
}
.ie .selector {
    standard-property-b: 20px;
}
.ie .selector {
    standard-property-a: 10px;
}

理想情况下,新规则只会在遍历整个规则后添加一次,但 PostCSS 似乎不允许 walkRules 函数内部的条件,所以我不确定如何阻止它为它看到的每个规则创建新规则.

我已经链接到上述代码的演示。任何关于更好架构的建议将不胜感激,就像我之前说的,我对此很陌生。谢谢!

演示

编辑:已解决。非常感谢安德烈·西特尼克!我已将他的答案标记为正确,因为其中的概念是我所需要的。对于那些寻找完整解决方案的人,请参阅以下代码(和演示!):

function isNotYetStandardProp (propName) {
    if (propName.indexOf('not-yet-standard-property-') > -1) {
      return true;
    }
    else {
      return false;
    }
}

function transformPropName (propName) {
    return propName.replace("not-yet-", "");
}

var skipNext = false;
var convertedProps = [];
var newRule;
var newNode;

return function (css) {

    css.walkRules(function(rule) {
        // The skipNext flag is used to prevent walkRules from walking onto any
        // newly created rules and recursively creating new rules based on the
        // newly added rule.
        if (!skipNext) {
            // Reset to remove values from last loop
            convertedProps = [];
            newRule = null;
            newNode = null;

            // Search through nodes of current rule and build up array
            // containing each property that needs to change.
            rule.nodes.filter(function (node) {
                if ((node.type === 'decl') && isNotYetStandardProp(node.prop)) {
                    newNode = node.clone();
                    newNode.prop = transformPropName(node.prop); 
                    convertedProps.push(newNode);
                }
            });

            // If there were properties to convert in this rule create a new
            // rule to put them in.
            if (convertedProps.length > 0) {
                newRule = rule.cloneAfter({ selector: '.ie ' + rule.selector });
                newRule.removeAll().append(convertedProps);
                skipNext = true;
            }
        }
        else {
            // We only want to skipNext once.
            skipNext = false;
        }
    })

}

解决方案演示

4

1 回答 1

1

您不需要walkDeclsinside walkRules,只需使用rule.nodes

css.walkRules(rule => {
    const nonStandard = rule.nodes.filter(node => {
        return if node.type === 'decl' && checkPropName(node.prop);
    });
    if ( nonStandard.length > 0 ) {
        const clone = rule.cloneAfter({ selector: '.ie ' + rule.selector });
        clone.append(nonStandard);
    }
})
于 2016-07-12T23:02:17.650 回答