繁体   English   中英

将css-modules应用于AngularJS的更好方法

[英]Better way of applying css-modules to AngularJS

我现在正在使用带有AngularJS 1.5组件的css-modules。 堆栈是webpack + css-loader?modules=true + angular 1.5 components + pug

目前,我必须执行以下步骤才能在我的pug模板中使用css模块。

// my-component.js

import template from 'my-component.pug';
import styles from 'my-component.css';

class MyComponent {
    constructor($element) {
        $element.addClass('myComponent');        // ------ (1)
        this.styles = styles;                    // ------ (2)
    }
}

angular.module(name, deps)
    .component('my-component', {
        controller: MyComponent,
        template: template,
    });

// my-component.pug
div(class={{ ::$ctrl.styles.fooBar }}) FooBar    // ----- (3)

// my-component.css
.myComponent { background: green; }
.fooBar { color: red; }

有两个问题:

  1. 每个组件都必须注入$element并手动设置其类名。 这样做的原因是,AngularJS组件标签本身存在于没有任何类的结果HTML中,这使得CSS变得困难。 例如,如果我像上面这样使用MyComponent

     <div> <my-component></my-component> </div> 

    它将生成以下HTML:

     <div> <my-component> <div class="my-component__fooBar__3B2xz">FooBar</div> </my-component> </div> 

    与ReactJS相比,上面结果中的<my-component>是一个额外的HTML,有时它会使CSS难以编写。 所以我的解决方案是(1),为它添加一个类。

  2. 模板中的类太长(3)。 我知道这是引用$ctrl.styles.fooBar的正确方法,但这太长了。

我理想的解决方案是这样的:

// my-component.js
angular.module(name, deps)
    .component('my-component', {
        controller: MyComponent,
        template: template,
        styles: styles,
    });

// my-component.css
div(css-class="fooBar") FooBar

这个想法是:

  1. make angular.module().component支持一个额外的styles属性,它将自动执行(2) this.styles = styles; 在控制器中,并应用(1) $element.addClass()
  2. 指令css-class$ctrl.styles应用于元素。

我的问题是,我不知道如何实现上面的想法1(2很容易)。 我很感激,如果有人能分享一些关于此的话。

我想出了一个我不太满意的解决方案。

Angular组件可以接受函数作为模板并使用$element注入。 DOC

如果template是一个函数,那么它将注入以下locals:

  • $ element - 当前元素
  • $ attrs - 元素的当前属性对象

因此,我们可以在模板函数中附加组件( .myComponent )的主类,然后正则表达式用编译的类名替换所有类名的出现。

// utils.js
function decorateTemplate(template, styles, className) {
    return ['$element', $element => {
        $element.addClass(styles[className]);
        return template.replace(/\$\{(\w+)\}/g, (match, p1) => styles[p1]);
    }];
}

// my-component.js
import style from './my-component.css';
import template from './my-component.pug';
import { decorateTemplate } from 'shared/utils';

class MyComponent {
    // NO NEED to inject $element in constructor
    // constructor($element) { ...
}

angular.module(name, deps)
    .component('myComponent', {
        // decorate the template with styles
        template: decorateTemplate(template, styles, 'myComponent'),
    });

// my-component.pug, with special '${className}' notation
div(class="${fooBar}") FooBar

还有一个地方需要改进, decorateTemplate使用正则表达式替换,模板必须使用特殊表示法${className}来指定css-modules类名。

欢迎任何建议。

UPDATE

我更新了我的decorateTemplate()函数以利用pug功能,因此本地类名称可以写为._localClassName

// utils.js
function decorateTemplate(template, styles, className) {

    return ['$element', ($element) => {
        $element.addClass(styles[className]);

        return template.replace(/\sclass="(.+?)"/g, (match, p1) => {
            let classes = p1.split(/\s+/);
            classes = classes.map(className => {
                if (className.startsWith('_')) {
                    let localClassName = className.slice(1);
                    if (styles[localClassName]) {
                        return styles[localClassName];
                    } else {
                        console.warn(`Warning: local class name ${className} not found`);
                        return className;
                    }

                } else {
                    return className;
                }
            });
            return ' class="' + classes.join(' ') + '"';
        });
    }];
}

// my-component.pug
._fooBar FooBar

虽然这更容易,但它并没有消除古怪的符号(以_开头为本地类名称)和正则表达式替换。

欢迎任何建议。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM