Стиль расширения/переопределения компонента многократного использования angular2
Предполагая, что мы хотим использовать компонент из некоторой библиотеки в angular2 (пример из material2). Компонентная аннотация выглядит следующим образом:
@Component({
moduleId: module.id,
selector: 'md-input',
templateUrl: 'input.html',
styleUrls: ['input.css'],
providers: [MD_INPUT_CONTROL_VALUE_ACCESSOR],
host: {'(click)' : 'focus()'}
})
Этот компонент поставляется с таблицей стилей по умолчанию "input.css". Если мы используем этот компонент в нашем приложении, мы, вероятно, захотим переопределить/расширить часть стиля, не копируя и не манипулируя самим компонентом. Как это сделать?
Возможное решение 1: Установите инкапсуляцию на "ViewEncapsulation.None":
На самом деле это не решение, просто обходной путь.
Возможное решение 2: Используйте ":: shadow" или "/deep/" в CSS:
Также работает, но его устарело в соответствии с спецификацией WebComponent.
Возможное решение 3. Используйте глобальный CSS и переопределите компонент CSS:
Работает также, но это нарушает концепцию тени DOM.
Возможное решение 4: переопределить непосредственно в шаблоне родительского компонента:
Пример:
<my-cmp [font-size]="100"></my-cmp>
Не подходит, если мы много переопределяем.
Возможное решение 5: переопределить или расширить определение "@Component" с помощью дополнительной таблицы стилей:
Кажется, это единственное правильное решение (по крайней мере для меня). Но я не знаю, как это сделать...
Любые советы по этому поводу? Может, у меня что-то не так...
Спасибо.
Ответы
Ответ 1
Для решения 5 вам необходимо создать подкласс для целевого компонента, создать пользовательский декоратор, который обрабатывает/переопределяет метаданные и устанавливает его для текущего подкомпонента.
Вот пример:
@CustomComponent({
styleUrls: ['css/style.css']
})
export class OverridenComponent extends SomeComponent {
}
Декоратор CustomComponent
будет выглядеть так:
export function CustomComponent(annotation: any) {
return function (target: Function) {
var parentTarget = Object.getPrototypeOf(target.prototype).constructor;
var parentAnnotations = Reflect.getMetadata('annotations', parentTarget);
var parentAnnotation = parentAnnotations[0];
Object.keys(parentAnnotation).forEach(key => {
if (!isPresent(parentAnnotation[key])) {
annotation[key] = parentAnnotation[key];
}
});
var metadata = new ComponentMetadata(annotation);
Reflect.defineMetadata('annotations', [ metadata ], target);
}
}
См. этот вопрос для получения дополнительной информации:
Ответ 2
Начиная с Angular 2.3, мы можем использовать наследование компонентов. Чтобы выполнить решение 5, мы могли бы это сделать.
//This is our base component that we want to override
@Component({
selector: 'pagination',
templateUrl: './pagination.component.html',
styleUrls: ['./pagination.component.css']
})
export class PaginationComponent {
}
//This inherits from our base component and uses a different style sheet.
@Component({
selector: 'pagination2',
//This is sharing the template with the parent class. Note
//this needs to be included since templateUrl doesn't automatically
//inherit.
templateUrl: './pagination.component.html',
//This is using a unique css file
styleUrls: ['./pagination2.component.css']
})
export class PaginationComponent2 extends PaginationComponent {
}
Ответ 3
Возможное решение 2: Используйте ":: shadow" или "/deep/" в CSS:
Это применимо только в том случае, если вы используете ViewEncapsulation.Native
.
Если вы используете ViewEncapsulation.Emulated
(по умолчанию), то Angular использует его собственную интерпретацию /deep/
и ::shadow
, а устаревание не применяется.
Если вы используете ViewEncapsulation.Native
, тогда вам пока что не повезло, потому что устаревшие браузерные ::shadow
и /deep/
глубоко устарели, а Angular еще не предоставил поддержки для поддержки тем для ViewEncapsulation.Native
, как для пример. Полимер делает с (полифильмированными) переменными CSS и миксинами.
Ответ 4
В Angular 4 мы можем переопределить стиль с помощью селектора псевдо-класса ::ng-deep
из таблицы стилей унаследованного класса.
:host ::ng-deep element {
//your style here
}
Для получения дополнительной информации см. http://blog.angular-university.io/angular-ngclass-ngstyle/