扩展/覆盖可重用angular2组件的样式

时间:2016-06-01 12:06:17

标签: angular

假设我们想在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:在CSS中使用“:: shadow”或“/ deep /”:
也可以,但根据WebComponent规范弃用了它。

可能的解决方案3:使用全局CSS并覆盖组件CSS:
也可以,但它违反了影子DOM概念。

可能的解决方案4:直接在父组件的模板中覆盖:

示例:

<my-cmp [font-size]="100"></my-cmp>

如果我们做了很多重写,那是不是真的适合。

可能的解决方案5:以某种方式使用其他样式表覆盖或扩展“@Component”定义:
这似乎是唯一正确的解决方案(至少对我而言)。但我不知道该怎么做......

对此有何建议?也许我有点不对劲...... 感谢。

4 个答案:

答案 0 :(得分:12)

在Angular 4中,我们可以使用继承的类样式表中的::ng-deep伪类选择器覆盖样式。

:host ::ng-deep element {
    //your style here
}

有关更多信息,请参阅http://blog.angular-university.io/angular-ngclass-ngstyle/

答案 1 :(得分:11)

对于解决方案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 :(得分:7)

  

可能的解决方案2:在CSS中使用“:: shadow”或“/ deep /”:

仅当您使用ViewEncapsulation.Native时才适用。

如果您使用ViewEncapsulation.Emulated(默认),则Angular会使用它自己对/deep/::shadow的解释,弃用不适用。

如果您使用ViewEncapsulation.Native,那么您目前运气不佳,因为浏览器原生::shadow/deep/深度已被弃用,Angular尚未提供对{的主题支持的任何支持{1}}例如,Polymer使用(polyfilled)CSS变量和mixins。

答案 3 :(得分:7)

从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 {
}