将 css 模块应用于 AngularJS 的更好方法
Better way of applying css-modules to AngularJS
我现在正在使用 css-模块和 AngularJS 1.5 组件。堆栈是 webpack
+ css-loader?modules=true
+ angular 1.5 components
+ 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; }
有两个问题:
每个组件都必须注入 $element
并手动设置其 class 名称。这样做的原因是,AngularJS组件标签本身存在于结果HTML中,没有任何classes,这使得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),给它加一个class。
模板中的 class 太长 (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
想法是:
- make
angular.module().component
支持一个额外的 styles
属性,它会在控制器中自动执行 (2) this.styles = styles;
,并应用 (1) $element.addClass()
。
- 指令
css-class
将 $ctrl.styles
应用于元素。
我的问题是,我不知道如何实现上面的想法 1(2 很简单)。如果有人可以就此分享一些信息,我将不胜感激。
我提出了一个我不太满意的解决方案。
Angular 组件可以接受函数作为模板并使用 $element
注入。
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
) 的主要 class,然后正则表达式将所有出现的 class 名称替换为已编译的 class名字。
// 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 class名字。
欢迎提出任何建议。
更新
我更新了我的 decorateTemplate()
函数以利用哈巴狗的特性,因此本地 class 名称可以写成 ._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
虽然这更容易,但它并没有消除古怪的符号(本地 class 名称以 _
开头)和正则表达式替换。
欢迎提出任何建议。
我现在正在使用 css-模块和 AngularJS 1.5 组件。堆栈是 webpack
+ css-loader?modules=true
+ angular 1.5 components
+ 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; }
有两个问题:
每个组件都必须注入
$element
并手动设置其 class 名称。这样做的原因是,AngularJS组件标签本身存在于结果HTML中,没有任何classes,这使得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),给它加一个class。模板中的 class 太长 (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
想法是:
- make
angular.module().component
支持一个额外的styles
属性,它会在控制器中自动执行 (2)this.styles = styles;
,并应用 (1)$element.addClass()
。 - 指令
css-class
将$ctrl.styles
应用于元素。
我的问题是,我不知道如何实现上面的想法 1(2 很简单)。如果有人可以就此分享一些信息,我将不胜感激。
我提出了一个我不太满意的解决方案。
Angular 组件可以接受函数作为模板并使用 $element
注入。
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
) 的主要 class,然后正则表达式将所有出现的 class 名称替换为已编译的 class名字。
// 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 class名字。
欢迎提出任何建议。
更新
我更新了我的 decorateTemplate()
函数以利用哈巴狗的特性,因此本地 class 名称可以写成 ._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
虽然这更容易,但它并没有消除古怪的符号(本地 class 名称以 _
开头)和正则表达式替换。
欢迎提出任何建议。