2

利用css var函数让你的组件样式输出规范样式API,可定制性更高; - 灰色的蓝猫

 1 year ago
source link: https://www.cnblogs.com/hrw3c/p/17387649.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

利用css var函数让你的组件样式输出规范样式API,可定制性更高;

我们平时在使用Elementui Antdesing这些UI库时,难免会碰到使用deep强行侵入式去修改组件内部样式的情况;
比如下列代码,我们需要把ant的分页样式进行高度自定义,就得使用deep去修改;
820792-20230510115051562-1740260078.jpg
这种实现方式确实能够达到我们的目的,但在开发时确总觉得不太合适:
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函数实现一个可自定义大小,颜色,以及子元素样式的卡片
820792-20230510115051538-1814882215.jpg
//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文档则可明确规定样式定制属性了:
820792-20230510115051512-2025101209.jpg
组件使用方式:
//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传过来计算的参数,比如下列代码:

820792-20230510122333640-1002055350.png

 这种我们也可以把这些全提出来使用style属性。让样式与js参数彻底隔离

//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结合去计算你想要的值
//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>
但是这种实现有命名空间的问题
所以需要稍微注意下变量命名,最好加独有的命名规则。防止变量覆盖;
//比如这样
.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、命名空间问题导致命名会有点长。
欢迎分享更好的解决方案。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK