回顾:组件库样式问题整理

记在封装组件库时,遇到的样式问题

背景

组件库使用 element-ui 2.13.0, 最后会将组件样式和element-ui中使用到的组件的样式, 打包成一个 css 文件.

现象

  1. 在旧平台(element: 1.3) 引入组件库以及样式

  1. 可以看到, 组件库中element-ui 2.13.0checkbox 样式, 影响了旧平台中的checkbox

希望达到的效果

让组件库中涉及element-ui 组件的样式, 只作用于组件库中的组件

尝试过的方法

  • 方式一: 组件引入element 组件样式时, 增加 scoped
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<Checkbox :label="test"> Checkbox Here </Checkbox>
</template>

<script>

// 引入 element 的 el-checkbox
import Checkbox from "element-ui/lib/checkbox";
export default {
components: { Checkbox }
};
</script>

<!-- 引入 element el-checkbox 样式, 增加scoped -->
<style src="element-ui/lib/theme-chalk/checkbox.css" scoped></style>

problem:

这种方式, 将样式引入写在父组件了, 但 <style scoped> 仅仅会影响到当前组件, 会为当前组件的 dom 节点增加data-v-xxx属性, 并为所有 css 样式增加 [data-v-xxx] 属性选择器, 如下图:


  • 方式二: 组件库在编写组件时, 最外层增加namespace
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<template>
<!-- 命名空间 admin-ui -->
<div class="admin-ui">
<Checkbox :label="test"> Checkbox Here </Checkbox>
</div>
</template>


<script>
// 引入 element 的 el-checkbox
import Checkbox from "element-ui/lib/checkbox";
export default {
components: { Checkbox }
};
</script>

<style lang="scss">
<!--引入 element el-checkbox 样式/字体文件, 增加命名空间 .admin-ui -->
.admin-ui {
$--font-path: "~element-ui/lib/theme-chalk/fonts";
@import "~element-ui/packages/theme-chalk/src/base.scss";
<!-- el-checkbox 的样式 -->
@import "~element-ui/packages/theme-chalk/src/checkbox.scss";
}

</style>

problem:

当遇到会插入到 body的组件(例如弹出框 el-popover)时, 命名空间不生效


  • 方式三 : scoped + deep
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<template>
<Checkbox :label="test"> Checkbox Here </Checkbox>
</template>

<script>
// 引入 element 的 el-checkbox
import Checkbox from "element-ui/lib/checkbox";
export default {
components: { Checkbox }
};
</script>

<style lang="scss" scoped>
<!--或者 /deep/ -->
::v-deep {
<!--引入字体样式-->
$--font-path: "~element-ui/lib/theme-chalk/fonts";
@import "~element-ui/packages/theme-chalk/src/base.scss";
<!--引入 element el-checkbox 样式-->
@import "~element-ui/lib/theme-chalk/checkbox";
}
</style>

problem:

该方法本质上会生成: [data-v-xxx] .el-checkbox {},相当于 [data-v-xxx]为命名空间[Emm] 对于 el-datepicker 等生成弹出框并插入body的组件同样不生效, el-select可以将弹出框限制不插入body, 而 el-datepicker 不行. 需梳理哪一些组件提供了 append-to-body 的 props


append-to-body prop

针对方式三, 只要将弹出框限制不插入到 body 即可

只要在源码中引入了 El-popover 或者 element-ui/src/utils/vue-popover mixin 的组件均包含 append-to-body

有一些组件虽然支持 append-to-body = false, 但是并没有在官方文档中体现 , 不排除会有问题出现, 或者升级之后 append-to-body 可能被去除(固定 element 版本即可)

相关的组件以及插入到 body 的 prop:

popper-append-to-body:

  • el-select
  • el-autocomplete

append-to-body:

  • el-cascader
  • el-datepicker
  • el-popover
  • el-color-picker (! not work) ****
  • el-drawer
  • el-dropdown (!需要加在子级 el-dropdown-menu, 但展示有问题, 需设置 style="width:max-content")
  • el-timepicker
  • el-tooltip
  • el-dialog (默认 false)

model-append-to-body:

  • el-dialog

Other problems

  • 组件内部的 show-tooltip ?

解决方法: tooltip 样式设置为全局 ok, 因为 element1.4 与 2.13 样式是相同的

  • element 组件内部引用了其他组件, 例如 el-pagination 内使用了 el-select, 无法修改 append-to-body ?

解决方法: 增加自定义类名, 并手动设置 dropdown 样式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<Pagination popper-class="custom-popper"/>
<style lang="scss">
.custom-popper {
// 引入 select 样式
@import '~element-ui/lib/theme-chalk/select';
// 设置 dropdown 样式
&.el-select-dropdown {
position: absolute;
z-index: 1001;
border: 1px solid #e4e7ed;
border-radius: 4px;
background-color: #fff;
-webkit-box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
-webkit-box-sizing: border-box;
box-sizing: border-box;
margin: 5px 0;
}
}
</style>
  • $message / $confirm / $notification ?

解决方法: 不使用该类提示, 抛出事件, 由外部处理.

  • 第三方库样式 ?

解决方法: 增加命名空间即可.

  • 组件引入顺序引起的样式冲突, 如 select 中的 scroll__wrap, 如果 select 放在 cascader 后引入, 会影响 cascader 的样式

解决方法: 目前发现 cascader 会受影响, 将 cascader 放在最后引入

  • dart-sass 打包的字体乱码?

解决方法: 换成 node-sass ✔️, 在 vue-cli 增加以下配置:

1
2
3
4
5
6
7
8
// npm i node-sass -D
css: {
loaderOptions: {
sass: {
implementation: require('node-sass')
}
}
}
  • 打包后@font-face 样式有问题, 会变成, ::v-deep没有成功解析 :
1
2
3
4
5
6
7
@font-face{
::v-deep {
font-family:element-icons;
src:url(fonts/element-icons.535877f5.woff);
.....
}
}

暂用正则替换 ::v-deep解决: packages/admin-ui/build/fix-deep.js