写在开头
通过上一篇文章 ElementUI源码系列一 - 从零搭建项目架构,项目准备、项目打包、项目测试流程 的学习,我们搭好了项目的基本框架,如下,它们每个文件夹是各司其职,分工明确的。
这一章我们来学习一下,ElementUI 中样式是如何被使用的,我们先来分析一波:
- 观察 element-ui 源码的 package.json 文件,可以知道它样式使用的是 scss 预处理语言;
- 在它的源码 packages/theme-chalk/src 路径下,我们还可以发现每个组件都有对应的 .scss 文件;
- .scss 文件最终肯定是要变成 .css 文件才能被浏览器识别的,那么它又是如何转换的呢?从 package.json 文件可以知道它使用了 gulp 来做转换,在 packages/theme-chalk/src 目录下也有关于它的配置文件。(关于 gulp 可以先自行学习一下,后面会用它写一些功能)
(为了方便学习,你可以下载一份 element-ui 源码在本地进行对比学习,效果会更佳)
使用scss预处理器编写组件样式
经过上面的分析,我们先来尝试使用 .scss 来给组件添加一些样式,再逐步也将它进行转换。首先,我们先来把我们组件代码改一改,给 button 组件添加一个类名。
// button.vue
<template>
<button class="el-button">我是一个普通按钮</button>
</template>
<script>
export default {
name: 'ElButton'
};
</script>
其次,我们也和 ElementUI 一样,在相同目录下,给 button 组件创建相同的样式文件。
并给它写一个最简单的样式,随便先给一个背景色,能看出效果即可,后面会使用一些 scss 语法来编写样式:
// button.scss
.el-button {
background-color: red;
}
最后,我们引入处理 .scss 需要用到的包,一共会用到四个包:npm install gulp@4.0.0 gulp-autoprefixer@6.0.0 gulp-cssmin@0.2.0 gulp-sass@4.0.2 -D
稍微介绍下四个包的作用:
- gulp:一种自动化构建工具,和我们熟知的 webpack 很相似,但它更纯粹一些,它基于 Node 流的能力去构建任务流,某些方面上更具性能优势,我们会采取它来处理 .scss 文件。
- gulp-autoprefixer:由它的名字大概也能猜出它的作用了,用于自动补全 CSS 前缀的插件。
- gulp-cssmin:用于压缩 CSS。
- gulp-sass:编译 scss,转成 CSS。
小知识:sass 和 scss 其实就是同一种东西,我们平时都称之为 sass ,它们俩的主要区别在于语法上,sass 是缩进语法为主,完全省略花括号;scss 是一种 CSS-like 语法,就比较接近 CSS ,更加友好和可读。
使用gulp把scss转成css、补全、压缩
写完 button.scss 样式文件后,要让它生效的第一步工作,我们就要把它转成 .css 文件才行。下面就正式开始 scss 的转换工作,我们先在 packages/theme-chalk 路径下创建一个 gulpfile.js 文件。
再编写 gulp 代码,代码不多,都是 gulp 插件使用的基本语法,应该不难哈。
// gulpfile.js
const { series, src, dest } = require('gulp');
const sass = require('gulp-sass');
const autoprefixer = require('gulp-autoprefixer');
const cssmin = require('gulp-cssmin');
function compile() {
return src('./src/*.scss')
.pipe(sass.sync()) // 转成CSS
.pipe(autoprefixer({
browsers: ['ie > 9', 'last 2 versions'],
cascade: false
})) // 补全
.pipe(cssmin()) // 压缩
.pipe(dest('./lib')); // 在当前目录下的lib文件夹输出最终文件
}
exports.build = series(compile);
写完配置文件,老样子,我们为这个转换操作配置一条命令,方便后期操作。
"scripts": {
"dev": "webpack-dev-server --config build/webpack.common.js",
"build": "webpack --config build/webpack.common.js",
"build:theme": "gulp build --gulpfile packages/theme-chalk/gulpfile.js"
},
现在在我们的项目的 package.json 文件中就有三条操作命令了,要注意记得它们分别的作用哦!
之后我们执行命令: npm run build:theme。
应该可以看到会有一个 lib 文件夹与 .css 文件的生成,这样就完成了 .scss 文件到 .css 文件的转换,并会自动补全 CSS 前缀和压缩了 CSS(补全功能,你可以尝试使用一些有兼容性的样式试试看,这里就不多说了)。
使用cp-cli移动css文件
生成好了 css 文件后,就完了吗?要如何使用呢?这就需要我们回头想想,我们平常是如何使用 ElementUI 的样式文件的。
我从 官网 上截了一张图,图中可以看到样式的引入,是在 element-ui 文件夹下的,并且它引的是一个 index.css ,我们可以先找到它对应的 .scss 文件看看:
这应该是一个总入口样式文件,它引入所有组件的样式文件。那我们不管三七二十一,也照葫芦画瓢,先来把这个总样式文件 index.scss 创建好:
它内容也简单,我们现在只有一个组件,所以只有一行而已:
// index.scss
@import "./button.scss";
然后你可以再次执行刚才的命令:npm run build:theme。
可以看到 index.css 就生成完了。
根据上面官网引入的路径,接下来我们只需要把所有的样式文件都移动到根目录下的 lib 文件夹就大功告成了。
这个操作会借用到一个包:npm install cp-cli@1.0.2 -D。
下完 cp-cli 包后,我们把 theme:build 命令改一改:
"scripts": {
"dev": "webpack-dev-server --config build/webpack.common.js",
"build": "webpack --config build/webpack.common.js",
"build:theme": "gulp build --gulpfile packages/theme-chalk/gulpfile.js && cp-cli packages/theme-chalk/lib lib/theme-chalk"
},
然后执行命令,观看根目录 lib 文件夹,神奇的事情是不是就发生了?(≧ω≦)(好吧,其实也不是很神奇)
测试组件的样式文件
做了那么多事情,又来到最后一步了,测试阶段,那么如何测试我们写的样式呢?
在上一篇文章 ElementUI源码系列一 - 从零搭建项目架构,项目准备、项目打包、项目测试流程 最后我们介绍了两种测试方式,下面我们用第一种方式 项目打包成本地npm包 来测试组件的样式。
测试详情过程可以去看上一篇文章,就不多介绍啦,总的来说,就是敲命令:
原本项目:npm run build:theme npm run build npm pack 测试项目:npm install 本地放置tgz包的全路径 npm run serve (重启项目)
然后在 main.js 引入样式:
import juejinElementUI from 'juejin-element-ui';
import 'juejin-element-ui/lib/theme-chalk/index.css'; // 引入样式
Vue.use(juejinElementUI);
最后放个效果图:
用scss编写样式美化button组件
我们稍微来把我们丑出天际的 button 组件美化美化,顺便用用 scss 的本来语法。当然,如果你对 scss 很熟了,你也可以跳过,这不是重点内容。
下面我们会创建如下图红框的一些文件,这是和 ElementUI 一样的目录,它的目录、文件划分还是很合理的,是值得我们参考学习的。
我们对 button.scss 样式文件进行改造:
// button.scss
@import "common/var";
@import "mixins/mixins";
@include b(button) {
background: $--button-default-background-color;
color: $--button-default-font-color;
border-color: $--button-default-border-color;
padding: 10px 16px;
border: 1px solid #ccc;
border-radius: 30px;
}
var.scss 是整个项目的主题定义:
// var.scss
$--color-white: #FFFFFF !default;
$--button-default-background-color: $--color-white !default;
$--color-text-regular: #606266 !default;
$--button-default-font-color: $--color-text-regular !default;
$--border-color-base: #DCDFE6 !default;
$--button-default-border-color: $--border-color-base !default;
minxins.scss 是存放一些具有相同性质的混入,比如我们下面用到的给每个类名都添加一个 el- 的操作。
// minxins.scss
@import "function";
@mixin b($block) {
$B: $namespace+'-'+$block !global;
.#{$B} {
@content;
}
}
function.scss 文件是存放一些 scss 函数,熟悉 scss 应该就比较了解了。
// function.scss
@import "config";
config.scss 定义了一些变量,有项目的标识 el,还有编写样式的规范 BEM ,关于 BEM 不了解的小伙伴要赶紧自行去学习一下啦。
// config.scss
$namespace: 'el';
$element-separator: '__';
$modifier-separator: '--';
$state-prefix: 'is-';
最后我们还是再放一张效果图: