我们平时在使用Elementui Antdesing这些UI库时,难免会碰到使用deep强行侵入式去修改组件内部样式的情况;比如下列代码,我们需要把ant的分页样式进行高度自定义,就得使用deep去修改;

这种实现方式确实能够达到我们的目的,但在开发时确总觉得不太合适:
1、他属于强行入侵组件内部去修改,虽然不会有大问题,但总觉得这种取巧方式有点不可取。
2、每次写deep时需要手动检查DOM元素进行编辑,UI文档中并不会有相关API文档;
为了解决心中的这两个结症,趁最近写组件的机会探索了下CSS 的var函数,发现他可以很好的解决以上问题。
利用var函数我们可以具体解决组件开发的以下问题:
1、组件样式自定义可以更加个性化
2、现在很多组件库实现一些样式控制还是依靠props传参的形式,这种var函数结合Style可完全避免props传参的情况,把样式跟props区分开;
3、在组件文档中可明确定制样式属性API;使组件样式可以跟Props属性一样以传参概念去进行高度定制,在使用组件样式时不需要像使用deep一样打开f12去一层一层的找
4、不会侵入式的改动组件内部样式
5、这个方案与deep互不排斥,如果开放的样式API不够用还是可以继续使用deep;
看下面需求,是如何利用css var函数实现一个可自定义大小,颜色,以及子元素样式的卡片

上代码
	
		
			| 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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | //Card.vue <template>     <div class="card">         <img class="card-img" :src="img" />         <p class="card-desc">{{ desc }}</p>     </div> </template> <style lang="scss" scoped>     .card {         // 这些以"--"开头的变量就是我们开放可自定义的样式属性了,可以在组件使用文档中明确开放         //卡片根元素样式         --width: 150px;         --height: auto;         --border-size: 1px;         --border-color: #ccc;         --border-radius: 5px;         --bg: #eee;         // 图片可定样式         --img-width: 130px;         --img-height: 130px;         --img-radius: 50%;         // 卡片描述样式         --desc-size: 16px;         --desc-line-height: 32px;         --desc-color: #333;         height: var(--height);         width: var(--width);         border: var(--border-size) solid var(--border-color);         border-radius: var(--border-radius);         background: var(--bg);         padding: 10px;         &-img {             width: var(--img-width);             height: var(--img-height);             border-radius: var(--img-radius);             overflow: hidden;         }         &-desc {             font-size: var(--desc-size);             color: var(--desc-color);             line-height: var(--desc-line-height);             text-align: center;         }     } </style> | 
	
这时候我们在API文档则可明确规定样式定制属性了:

组件使用方式:
	
		
			| 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 27 28 29 30 | //demo.vue <template>     <div >         <Card desc="我是默认的样式我是默认的样式我是默认的样式" :img="img" />         <Card class="card_1" desc="自定义样式,子元素图片变小了" :img="img" />         <Card class="card_2" desc="自定义样式,圆角没了,描述字变小了,高度高了" :img="img" />     </div> </template> <script>...</script> <style lang="scss" scoped>     .card_1 {         --width: 100px;         --height: 200px;         --border-radius: 20px;         --img-width: 80px;         --img-height: 50px;         --img-radius: 10px;         --desc-color: #f00;         --desc-size: 12px;         --desc-line-height: 21px;     }     .card_2 {         --height: 300px;         --border-radius: 0px;         --bg: #fff;         --img-radius: 50px;         --desc-size: 14px;         --desc-line-height: 21px;     } </style> | 
	
以上就是一个基本的组件实现;还种情况我们在使用UI库时也会碰到需要使用Props传过来计算的参数,比如下列代码:

这种我们也可以把这些全提出来使用style属性。让样式与js参数彻底隔离
	
		
			| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //demo.vue   <template>         <card             desc="我是默认的样式我是默认的样式"             :img="img"             :style="hoverStyle"             @mouseout="hoverStyle = {}"             @mouseover="handleHover"         /> </template> <script setup>     let hoverStyle = ref({});     const handleHover = () => {         hoverStyle.value = { '--bg': '#f0f', '--width': '180px' };     }; </script> | 
	
我们在组件内
JS可以使用props.style获取到设置的值,css中可以使用calc变量与var结合去计算你想要的值
	
		
			| 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 27 28 29 30 31 32 33 34 35 36 37 38 | //card.vue <template>     <div class="card" :style="style">         {{ width }}         <img class="card-img" :src="img" />         <p class="card-desc">{{ desc }}</p>     </div> </template> <script setup>     const $props = defineProps({         img: {             type: String,             default: '',         },         desc: {             type: String,             default: '',         },         style: {             type: Object,             default: () => ({}),         },     });     //假如你在js中需要用到宽度     let width = computed(() => {         return parseInt($props.style['--width'] || 150);     }); </script> <style lang="scss" scoped> .card{     ...     //假如你有个子级元素需要基于宽度计算     .item{         width: calc(var(--width) - 100)     }     ... } </style> | 
	
但是这种实现有命名空间的问题所以需要稍微注意下变量命名,最好加独有的命名规则。防止变量覆盖;
	
		
			| 1 2 3 4 5 | //比如这样 .ch-card{     --ch-card-width:100px;     --ch-card-height:100px; } | 
	
总结下这种方案的优缺点:
优点
1、组件样式自定义可以更加个性化
2、现在很多组件库实现一些样式控制还是依靠props传参的形式,这种var函数结合Style可完全避免props传参的情况,把样式跟props区分开;
3、在组件文档中可明确定制样式属性API;使组件样式可以跟Props属性一样以传参概念去进行高度定制,在使用组件样式时不需要像使用deep一样打开f12去一层一层的找
4、不会侵入式的改动组件内部样式
5、这个方案与deep互不排斥,如果开放的样式API不够用还是可以继续使用deep;
缺点:
1、开发组件时会工作量会增大,但是磨刀不误砍柴功
2、命名空间问题导致命名会有点长。