如何从CSS选择器中提取类名?

时间:2016-07-17 15:33:21

标签: javascript css parsing css-selectors eslint

故事:

我正在构建一个ESLint规则来警告在CSS选择器定位器中使用bootstrap面向布局和角度技术类。目前我在字符串方法中使用了一个简单的子字符串:

for (var i = 0; i < prohibitedClasses.length; i++) {
  if (node.arguments[0].value.indexOf(prohibitedClasses[i]) >= 0) {
    context.report({
      node: node,
      message: 'Unexpected Bootstrap class "' + prohibitedClasses[i] + '" inside a CSS selector'
    })
  }

但事实证明它并不可靠。例如,它会在.col-sm-offset-11 CSS选择器上引发错误2次,​​报告要使用的col-sm-offset-1col-sm-offset-11。我可以想象它可以很容易地打破使用多个伪类的更复杂的选择器。

问题:

从CSS选择器中提取类名的最可靠方法是什么?

以下是我们应该涵盖(待改进)的示例测试列表:

.col-sm-push-4                 // -> ['col-sm-push-4']
.myclass.col-lg-pull-8         // -> ['myclass', 'col-lg-pull-8']
[class*='col-md-offset-4']     // -> []
[class$=col-md-offset-11]      // -> []
[class~="col-md-10"] .myclass  // -> ['col-md-10', 'myclass']
.col-md-10,.col-md-11          // -> ['col-md-10', 'col-md-11']

请注意,我们需要跳过保留^=的{​​{1}},$=*=部分类过滤器值(感谢您的评论)。

1 个答案:

答案 0 :(得分:2)

有一个名为node-css-selector-parser的问题包专门设计,缺少“如何使用它”部分来提取类名。填补空白,这就是我如何应用它来解决问题。

使用~=,我们可以解析CSS选择器并根据结果类型分析用于点(例如node-css-selector-parser)的类名和在属性选择器中使用的类名(例如{{1 }}):

.myclass

(使用standard代码样式 - 例如,在行尾没有[class*=test]

这证明对我有用,并希望能帮助其他人解决类似的问题。请注意,在此状态下,此代码还会提取传递到// setup up CSS selector parser var CssSelectorParser = require('css-selector-parser').CssSelectorParser var parser = new CssSelectorParser() parser.registerSelectorPseudos('has', 'contains') parser.registerNestingOperators('>', '+', '~') parser.registerAttrEqualityMods('^', '$', '*', '~') parser.enableSubstitutes() function extractClassNames (rule) { var classNames = [] // extract class names defined with ".", e.g. .myclass if (rule.classNames) { classNames.push.apply(classNames, rule.classNames) } // extract class names defined in attributes, e.g. [class*=myclass] if (rule.attrs) { rule.attrs.forEach(function (attr) { if (attr.name === 'class') { classNames.push(attr.value) } }) } return classNames } module.exports = function (cssSelector) { try { var result = parser.parse(cssSelector) } catch (err) { // ignore parsing errors - we don't want it to fail miserably on a target machine during a ESLint run console.log('Parsing CSS selector: "' + cssSelector + '". ' + err) return [] } // handling empty inputs if (!result) { return [] } var classNames = [] if (result.type === 'ruleSet') { var rule = result.rule while (rule) { classNames.push.apply(classNames, extractClassNames(rule)) rule = rule.rule } } else if (result.type === 'selectors' && result.selectors) { result.selectors.forEach(function (selector) { classNames.push.apply(classNames, extractClassNames(selector.rule)) }) } return classNames } ;^=的部分类值,理想情况下需要跳过这些值。