最近因为处理 less 自动换主题和 less 的 css-module 的原因,使用了 post-css 这个库,被其强大的功能所吸引,所以写了这个小文章。
    首先我们初始化一个项目,我们可以直接使用我已经写好的脚手架 post-css-demo。 这个脚手架中实现了两个语法,一个是模仿 flutter image 容器的 BoxFit,实现的一个属性简写,支持了 fill ,contain ,cover, fitHeight, fitWidth。
    写法是这样的 :

    1. .bg-fill {
    2. background-color: #fff;
    3. /* fit: fill fitHeight cover contain */
    4. fit: url(https://flutter.io/assets/flutter-lockup-4cb0ee072ab312e59784d9fbf4fb7ad42688a7fdaea1270ccf6bbf4f34b7e03f.svg)
    5. fill;
    6. }

    并且实现了一个temp的属性,我约定 temp-开头的就是一个模板css,类似:

    1. .temp-base {
    2. width: 100%;
    3. height: 100%;
    4. }

    然后用法是这样的,prop 代表要用模板,base代码模板的名字。

    1. .bg-fill {
    2. background-color: #fff;
    3. temp: base;
    4. }

    所以以下代码

    1. .temp-base {
    2. width: 100%;
    3. height: 100%;
    4. }
    5. .bg-contain {
    6. background-color: #fff;
    7. /* fit: fill fitHeight cover contain */
    8. fit: url(https://flutter.io/assets/flutter-lockup-4cb0ee072ab312e59784d9fbf4fb7ad42688a7fdaea1270ccf6bbf4f34b7e03f.svg)
    9. contain;
    10. temp: base;
    11. }

    编译成一个 浏览器是别的css,就是这样:

    1. .bg-contain {
    2. background-color: #fff;
    3. background-size: contain;
    4. background-image: url(https://flutter.io/assets/flutter-lockup-4cb0ee072ab312e59784d9fbf4fb7ad42688a7fdaea1270ccf6bbf4f34b7e03f.svg);
    5. width: 100%;
    6. height: 100%;
    7. }

    主要利用了post-css的 walkRules 和 walkDecls 方法。walkRules 会遍历所有的 selector ,也就是一个 {} 包裹的部分,temp就是根据这个原理实现的。 获得 selector,如果selector中包含 temp-就把他的子节点存起来,等碰到 temp属性,去除并且将其替换。

    1. const tempMap = {};
    2. // 保存模板
    3. if (rule.selector && rule.selector.indexOf("temp-") > -1) {
    4. const tempName = rule.selector.split("-").pop();
    5. tempMap[tempName] = [...rule.nodes];
    6. rule.remove();
    7. return;
    8. }
    9. // 如果是模板属性
    10. if (decl.prop === "temp") {
    11. const value = decl.value;
    12. const decls = tempMap[value] as Declaration[];
    13. const newDecls = decls.map(decl => decl.clone());
    14. if (decls) {
    15. decl.replaceWith(newDecls);
    16. }
    17. }