javascript - 将 css 模块应用于 AngularJS 的更好方法

标签 javascript css angularjs css-modules

我现在正在使用带有 AngularJS 1.5 组件的 css 模块。堆栈是 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. 每个组件都必须注入(inject) $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. 制作angular.module().component支持额外的 styles属性,它将自动执行 (2) this.styles = styles;在 Controller 中,并应用 (1) $element.addClass()以及。
  2. 指令 css-class申请$ctrl.styles到元素。

我的问题是,我不知道如何实现上面的想法 1(2 很简单)。如果有人可以就此分享一些信息,我将不胜感激。

最佳答案

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

Angular 组件可以接受一个函数作为模板并使用 $element 注入(inject)。 doc

If template is a function, then it is injected with the following locals:

  • $element - Current element
  • $attrs - Current attributes object for the element

因此我们可以在模板函数中附加组件(.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 类名.

欢迎提出任何建议。

更新

我更新了我的 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

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

欢迎提出任何建议。

关于javascript - 将 css 模块应用于 AngularJS 的更好方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45974263/

相关文章:

javascript - AngularJS 与 Django - 模板标签冲突

javascript - AngularJS错误: [$injector:modulerr] 'ngRoute'

javascript - 使用 jQuery 将每个 * 包装在页面上

javascript - 为什么我的 javascript 表单不起作用?

jQuery Dropdown Mouseout 仅当在 div 之外时

css - 带有相邻选择器的空白

javascript - 尽管存在 Cookie,但未找到它

javascript - Google map api,如何处理同一位置的所有标记(重叠标记)的标记悬停事件?

android - 使用自定义 HTML 和预定义的基本 URL 将 CSS 文件从 Assets 加载到 WebView

angularjs - PouchDB 5.3.0 - 错误 : Database location or iosDatabaseLocation value is now mandatory in openDatabase call