在Angular1.5中,增加了一个Component方法,并且定义了组件的若干生命周期hook,在代码规范中也是推崇组件化开发,但是很遗憾的是,CSS模块化组件化的问题并没有得到解决,大部分项目的打包方式还是将所有CSS打包成一个完整的CSS文件,然后插入到html中,这样做的坏处显而易见,如果团队没有良好的CSS代码规范,很容易引起CSS的冲突,本文使用CSS Modules来解决Angular1.X中存在的CSS 冲突问题。

为了便于读者查看并动手操作,我将所有的代码打包成了一个库,首先在本地clone这个库

git clone https://github.com/myzhibie/ng1-css-modules-demo.git

接着安装所需要的依赖

npm install

上述过程如果成功,就可以运行了

gulp serve

在浏览器中查看结果http://localhost:3000

首先查看整个项目目录

client文件夹表示客户端代码,common目录下是一些公用组件,components目录下是非公用的业务组件,generator目录下是生成组件的模板文件,webpack.config.js是项目基础的webpack配置文件,根据开发环境会执行添加到dev或者production配置当中去。

CSS Modules是什么,怎么用

关于CSS Modules是什么,这里不多说,只阐述如何在项目中使用,好处也是显而易见的,就是彻底隔离了组件的CSS和全局的CSS,防止冲突。如果需要对CSS Modules有更深的概念上的认识,请查看官网

配置webpack中的css-loader,启用css-modules.

在项目根目录下webpack.config.js中,查看如下代码

 module.exports = {
devtool: 'sourcemap',
entry: {},
module: {
loaders: [
{ test: /\.js$/, exclude: [/app\/lib/, /node_modules/], loader: 'ng-annotate!babel' },
{ test: /\.html$/, loader: 'raw' },
{ test: /\.scss$/, loader: 'style!css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!sass' },
{ test: /\.css$/, loader: 'style!css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]' }
]
},
// resolve:{
// modulesDirectories:[bootstrapPath]
// },
plugins: [
// Injects bundles in your index.html instead of wiring all manually.
// It also adds hash to all injected assets so we don't have problems
// with cache purging during deployment.
new HtmlWebpackPlugin({
template: 'client/index.html',
inject: 'body',
hash: true
}), // Automatically move all modules defined outside of application directory to vendor bundle.
// If you are using more complicated project structure, consider to specify common chunks manually.
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: function (module, count) {
return module.resource && module.resource.indexOf(path.resolve(__dirname, 'client')) === -1;
}
})
]
};

注意查看第8和第9行,对于css和scss文件的处理,使用css-loader并启用了css-modules,importLoaders=1代码该文件被CSS-loader处理之后还会被Style-loader再次处理一次,localIdentName指定了scope css名字生成的规则,这里是[name]代表组件所在目录名,[local]表示本来定义的css名称,[hash:base64:5]代表由css-loader生成的哈希值。这样定义之后,每次遇到css或者sass文件,css-loader都会按照我们指定的方式将组件的css名称改名并引用到html中。

添加Scoped css(Sass)

所谓的scoped css,就是指局部css,在我们的项目中可以理解为单个组件自己的css,不与全局css相混淆。在client/app/components目录下,选定attrs组件,添加attrs.scss,内容如下:

 //local scope css 定义
.attrs{
color:red;
}
.header{
color:green;
}

接着在attrs.controller.js中引入这个sass文件,如下:

 import styles from "./attrs.scss";
class AttrsController {
constructor() {
this.name = 'Directives利用attrs通信';
this.styles=styles;
}
} export default AttrsController;

第一行import引入进来我们刚才写的css,然后将它赋值给该controller的一个属性叫styles,接着在html中引用我们定义的styles,如下:

 <navbar></navbar>
<div>
<h2 class="{{$ctrl.styles.header}}">{{ $ctrl.name }}</h2>
<directive-b directive-a></directive-b>
</div>

注意第3行,我们直接使用controller的styles对象加上我们定义的类名(header)来使用绑定类名,结果如下:

可以看到css-loader将我们定义的类名改成了我们指定的模式,并在html中引用了该类,可以查看我们引入的styles对象如下:

基本原理就是css-loader按照我们指定的模式修改每个组件的类名,并在我们import的时候将其打包到js中的一个对象,这个对象的key值是我们定义的原始类名,键值是修改后的类名。

通过查看原始的HTML代码,我们可以发现,css-loader最后将改名后的每个组件的css,全部以<style>的方式插入到html的header中,便于页面的引用,如下

以上就是CSS Modules的基本原理

验证是否存在CSS冲突

前面我们在attrs组件中添加了一个.header类,值为color:green,接着我们以同样方式在about组件中添加一个.header类,值为 color: red;结果如下:

attrs组件

about组件

可以看到尽管我们定义的原始类名都是.header,但是被css-loader修改后的类名是不一样的,所以在每个组件下定义的类即使同名也是不会发生冲突的,这就是scoped css的原理。

global css

我们实现了scoped css,又会问如果我想给全局添加一css怎么办呢?其实很简单,global css的实现引入方式和scoped css并没有区别,只是在类的定义上有区别,如下,在app目录下定义一个app.scss文件,内容如下:

 body {
font-size: 20px;
} :global {
.index {
display:inline-block;
margin-top: 20px;
}
}

注意第五行,使用:global定义的就是一个全局类,在项目任何地方都可以使用,比如我们在about组件中定义了一个directive,就可以在这个directive中使用index类,如下:

 function aDirective(homeService,$rootScope) {
"ngInject";
return {
restrict: 'E',
template: `name:<input type='text' ng-model='showValue' class='about'>
<br><button ng-click="addName()" class="index">addName</button>`,
link: (scope, element, attrs) => {
scope.addName = () => {
if(scope.showValue){
$rootScope.$broadcast('addName',scope.showValue);
}
}
}
};
} export default aDirective;

注意第六行,就是直接指定类名为index,结果如下:

在css modules中使用sass嵌套定义类名

对于大型项目来讲,很少有直接使用css的,通常都是使用一些CSS预处理器,比如说Sass,在Sass中,通常类之间可以嵌套定义,配合CSS Modules,也是能够灵活使用,比如在about组件中,定义about.scss嵌套类名如下:

 //嵌套定义,只需要写类名即可,不需要嵌套调用
.sec {
.about {
display: inline-block;
margin-bottom: 10px;
}
} .header {
color: red;
}

我们定义了一个.sec类,并且在该类下定义了一个嵌套的about类,在html中使用如下:

 <navbar></navbar>
<h2 class="{{$ctrl.styles.header}}">{{ $ctrl.name }}</h2>
<section class="{{$ctrl.styles.sec}}">
<event-adirective class="{{$ctrl.styles.about}}"></event-adirective>
<event-bdirective></event-bdirective>
</section>

注意第4行,我们并没有在使用about类的时候,在前面加上sec,这说明CSS Modules 在处理styles对象的时候认为所有类的类名都是平级关系,尽管它们在定义的时候是嵌套定义的,但是要让这些嵌套类起作用,必须按照嵌套的结构来添加类,结果如下:

使用CSS Modules的多个css文件合并功能

由于CSS Modules的主要思想是使用js来处理CSS,那么对于不同的CSS我们可以将其合并成一个styles对象,例如在ctrls组件中,定义两个sass文件,

a.scss

 //多个scss文件合并
.aCtrls{
color: purple;
}

ctrls.scss

.ctrls {
button {
display: inline-block;
margin: 20px;
}
}

在ctrls.controller.js中进行合并

 let styles={};
import aStyle from './a.scss';
import bStyle from './ctrls.scss';
Object.assign(styles,aStyle,bStyle);
class CtrlsController {
constructor() {
this.name = 'directive通过Controllers通信';
this.styles=styles;
}
} export default CtrlsController;

在1到4行,通过引入不同的styles文件,并将它们合并为一个对象,然后在ctrls.html中使用

 <navbar></navbar>
<div>
<h1 class='{{$ctrl.styles.aCtrls}}'>{{ $ctrl.name }}</h1>
<a-ctrl-directive>
<div>
<div>
<b-ctrl-directive class='{{$ctrl.styles.ctrls}}'></b-ctrl-directive>
</div>
</div>
</a-ctrl-directive> </div>

和使用一个sass文件定义的在使用上完全没有任何区别。

以上就是CSS Modules在Angular1.X项目中的使用,我们还可以结合PostCSS让它在功能上更加强大,进一步使用可以参考这里

在Angular1.X中使用CSS Modules的更多相关文章

  1. 在React中使用CSS Modules设置样式

    最近,一直在看React...那真的是一个一直在学的过程啊,从配置环境webpack,到基础知识jsx,babel,es6,没有一个不是之前没有接触的.其实,我内心是兴奋的啊,毕竟,活着就是要接触一些 ...

  2. 在vue中使用css modules替代scroped

    前面的话 css modules是一种流行的模块化和组合CSS的系统. vue-loader提供了与css modules的集成,作为scope CSS的替代方案.本文将详细介绍css modules ...

  3. taro CSS Modules 的使用

    Taro 中内置了 CSS Modules 的支持,但默认是关闭的,如果需要开启使用,请先在编译配置中添加如下配置. 小程序端开启 weapp: { module: { postcss: { // c ...

  4. CSS modules 与 React中实践

    最近一直在学习React,看上去蛮简单的内容,其实学习曲线还是比较高的. 目前学到css绑定的问题,看到有一篇好的文章,就转过来了. CSS 模块化的解决方案有很多,但主要有两类.一类是彻底抛弃 CS ...

  5. Webpack 2 视频教程 012 - 理解Webpack 中的 CSS 作用域与 CSS Modules

    原文发表于我的技术博客 这是我免费发布的高质量超清「Webpack 2 视频教程」. Webpack 作为目前前端开发必备的框架,Webpack 发布了 2.0 版本,此视频就是基于 2.0 的版本讲 ...

  6. create-react-app 搭建的项目中,使用 CSS Modules

    create-react-app 搭建的项目中,使用 CSS Modules: 修改config目录下 webpack.config.dev.js 和 webpack.config.prod.js 文 ...

  7. 转 : CSS Modules详解及React中实践

    https://zhuanlan.zhihu.com/p/20495964 CSS 是前端领域中进化最慢的一块.由于 ES2015/2016 的快速普及和 Babel/Webpack 等工具的迅猛发展 ...

  8. CSS Modules入门及React中实践(内附webpack4配置)

    本篇文章以整理为主,自己进行了部分修改,如有侵权,请告知 CSS Modules介绍 CSS Modules是什么东西呢?首先,让我们从官方文档入手:GitHub – css-modules/css- ...

  9. vue中scoped vs css modules

    注意:此文是默认你已经具备scoped和css modules的相关基础知识,所以不做用法上的讲解. 在vue中,我们有两种方式可以定义css作用域,一种是scoped,另一种就是css module ...

随机推荐

  1. KTV项目 SQL数据库的应用 结合C#应用窗体

    五道口北大青鸟校区 KTV项目 指导老师:袁玉明 歌曲播放原理 SQL数据库关系图 C#解决方案类图 第一步:创建数据库连接方法和打开方法和关闭方法! public class DBHelper { ...

  2. ASP.net封装

    设计如下: 代码: using System; using System.IO; public partial class 四则运算 : System.Web.UI.Page { protected ...

  3. xmlrpc实现bugzilla api调用(无会话保持功能,单一接口请求)

    xmlrpc实现bugzilla4   xmlrpc api调用(无会话保持功能,单一接口请求),如需会话保持,请参考我的另外一篇随笔(bugzilla4的xmlrpc接口api调用实现分享: xml ...

  4. autolayout sizeclass 资料集锦

    http://www.raywenderlich.com/20881/beginning-auto-layout-part-1-of-2 Core Animation Programming Guid ...

  5. A Simple Problem with Integers_树状数组

    Problem Description Let A1, A2, ... , AN be N elements. You need to deal with two kinds of operation ...

  6. aspx前台调用cs后台方法

    随着对于mvc的习惯使用,aspx页面渐渐用的不怎么用了,主要是生命周期感觉上比较慢,要么就用html+handler一般处理程序来装下逼.虽然不用,但还是要给刚工作的人讲下,相信不少人都想过:既然前 ...

  7. [转] Jenkins实战演练之Windows系统节点管理

    [前提] 通过<Jenkins实战演练之Windows服务器快速搭建>(http://my.oschina.net/iware/blog /191818)和<Jenkins实战演练之 ...

  8. win7 64位安装pygame

    需要的工具包 Python安装包 Pip安装包(版本无要求) Pygame安装包(版本需要与python匹配) http://jingyan.baidu.com/article/425e69e6ed3 ...

  9. iftop 安装以及相关参数及说明(转载自csdn)

      转载自http://blog.csdn.net/cqinter/article/details/6250211 关于 Iftop iftop 是类似于top的实时流量监控工具.主要用来显示本机网络 ...

  10. python打开文件的模式

    r打开只读文件,该文件必须存在. r+打开可读写的文件,该文件必须存在. w打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失.若文件不存在则建立该文件. w+打开可读写文件,若文件存在则文 ...