2017-08-31 49 views
11

Używam teraz modułów css z komponentami AngularJS 1.5. Stos to webpack + css-loader?modules=true + angular 1.5 components + pug.Lepszy sposób zastosowania modułów css do AngularJS

Obecnie muszę wykonać następujące kroki, aby użyć modułów css w moim szablonie mops.

// 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; } 

Istnieją dwa problemy:

  1. Każdy element musi wstrzykiwać $element i ustawić jego nazwę klasy ręcznie. Powodem jest to, że znacznik komponentu AngularJS sam istnieje w wynikowym kodzie HTML bez żadnych klas, co utrudnia CSS. Na przykład, jeśli mogę użyć MyComponent powyżej tak:

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

    wygeneruje następujący kod HTML:

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

    porównaniu do ReactJS, <my-component> w powyższy wynik HTML jest dodatkowy, czasami to sprawia, CSS trudne pisać. Więc moim rozwiązaniem jest (1), aby dodać do niego klasę.

  2. Klasa w szablonie jest za długa (3). Wiem, że to jest poprawny sposób na odniesienie $ctrl.styles.fooBar, ale to jest o wiele za długo.

Moja Idealnym rozwiązaniem byłoby tak:

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

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

Chodzi o to, aby:

  1. zrobić angular.module().component wsparcie dodatkowy styles atrybut, który będzie automatycznie (2) this.styles = styles; w kontroler i zastosuj (1) $element.addClass() również.
  2. dyrektywa css-class do zastosowania $ctrl.styles do elementu.

Moje pytanie brzmi, nie mam pojęcia, jak zrealizować pomysł 1 powyżej (2 jest łatwe). Doceniam, czy ktokolwiek mógłby się o tym przekonać.

Odpowiedz

5

Wymyśliłem rozwiązanie, którego nie satysfakcjonuję.

Element kątowy może przyjąć funkcję jako szablon i wstrzyknąć $element. doc

Jeśli szablon jest funkcją, to jest wstrzykiwany z następujących miejscowych:

  • $ element - aktualny element
  • $ attrs - Aktualne atrybuty obiektu dla elementu

Dlatego możemy dołączyć główną klasę komponentu (.myComponent) do szablonu zabawy ction, a następnie regex zastępuje wszystkie wystąpienia nazw klas skompilowanymi nazwami klas.

// 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 

Istnieje jeszcze jedno miejsce, które należy poprawić wymianę decorateTemplate używa regex i szablon musi użyć specjalnej notacji ${className} określić nazwy klas CSS-moduły.

Wszelkie sugestie są mile widziane.

UPDATE

zaktualizowałem moją decorateTemplate() funkcję wykorzystać możliwości Mops, tak że nazwy miejscowej klasy mogą być zapisywane jako ._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 

Chociaż jest dużo łatwiej nie eliminuje ekscentryczne notacji (zacząć _ dla nazw lokalnych klasa) i regex zastąpić.

Wszelkie sugestie są mile widziane.