2017-08-31 66 views
11

我現在對AngularJS 1.5組件使用css模塊。該堆棧是webpack + css-loader?modules=true + angular 1.5 components + pug將AngularJS應用於css模塊的更好方法

目前我必須執行以下步驟在我的帕格模板中使用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. 使angular.module().component支持額外的styles屬性,它會自動完成(2)this.styles = styles;在控制器,並應用(1)$element.addClass()以及。
  2. 指令css-class$ctrl.styles應用於元素。

我的問題是,我不知道如何實現上面的想法1(2很容易)。我很感激任何人都可以分享這一點。

回答

5

我想出了一個我不太滿意的解決方案。

角度分量可以接受函數作爲模板並注入$elementdoc

如果模板是一個函數,那麼它被注入以下當地人:

  • $元素 - 當前元素
  • $ 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模塊類名。

歡迎任何建議。

UPDATE

我更新了我的decorateTemplate()功能利用哈巴狗功能,使局部類名可以寫爲._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 

雖然這是很容易不排除古怪的符號和正則表達式替換(與_本地類的名​​字開始)。

歡迎任何建議。

相關問題