先来看下效果图:
我是把进度条封装成组件ProgressBar.vue,由父组件传递需要展示的数组,然后循环数据实现整体效果。
其中修改slider颜色需要用到的类名为:
/* 滑动条颜色 */
.el-slider__bar {}
/* 滑块颜色 */
.el-slider__button {}
/* 滑动轨颜色 */
.el-slider__runway {}
由于设计要求滑块的中间会有个小圆点,如果大家需要实现的效果只有一种颜色的话,直接用css即可实现:
/* 滑块颜色 */
.el-slider__button {
border-color: #ff9c12;
background: rgba(79, 49, 7, 0.48);
&:after {
content: '';
display: block;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 7px;
height: 7px;
border-radius: 50%;
background: #ff9c12;
}
}
但因为这次的需求是按预设颜色数组循环展示,所以我需要通过js去动态渲染颜色。
但是JS无法直接获取元素的::after伪元素节点,因为它不是DOM节点。可以使用getComputedStyle方法获取元素的样式,进而获取::after伪元素的内容。所以最开始我是想通过获取.el-slider__button的伪类节点然后改变他的backgroundColor属性
let sliderButton = document.querySelector(`.slider${i} .el-slider__button`) as HTMLElement
let sliderButtonAfter = getComputedStyle(sliderButton, '::after')
sliderButtonAfter.setProperty('backgroundColor', sliderButtonColors[index])
但是结果控制台报出了如下错误,提示无法修改只读属性:
Uncaught (in promise) DOMException: Failed to execute 'setProperty' on 'CSSStyleDeclaration': These styles are computed, and therefore the 'backgroundColor' property is read-only.
只好换一种方法咯,首先可以将切换的颜色设为一个变量,然后通过修改这个变量的值实现动态渲染的效果。这时候就可以用setProperty去设置这个属性的值了,试了一下果然可以!
// 在style里定义变量,并在伪元素里绑定
--slider-color: #0000;
.el-slider__button {
&:after {
background: var(--slider-color);
}
}
// script方法执行
sliderButton.style.setProperty('--slider-color', sliderButtonColors[index])
子组件ProgressBar.vue整体代码如下:
<template>
<div class="progress-contaioner">
<div class="slider-demo-block" v-for="(item, index) in props.progressList" :key="item.title">
<div class="progress-info">
<div class="progress-tltle">{{ item.title }}</div>
<div class="progress-proportion">
<span>{{ item.value }}</span>
<span class="proportion-maximums">/9000000</span>
<span class="proportion-unit">元</span>
</div>
</div>
<el-slider
v-model="item.value"
:class="`slider${index}`"
:max="9000000"
:min="0"
:show-tooltip="false"
disabled />
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted } from 'vue'
interface IProgressBar {
title: string
value: number
}
const props = withDefaults(
defineProps<{
progressList: IProgressBar[]
}>(),
{},
)
// 预设滑动条颜色数组
const sliderBarColors = [
'linear-gradient(270deg, #FF9C12 0%, rgba(253,114,25,0.32) 100%)',
'linear-gradient(270deg, #FFD570 0%, rgba(255,161,101,0.32) 100%)',
'linear-gradient(270deg, #FF6600 0%, rgba(253,114,25,0.32) 100%)',
]
// 预设滑块颜色数组
const sliderButtonColors = ['#FF9C12', '#FCD270', '#F86402']
const computedBarColor = () => {
for (let i = 0; i < props.progressList.length; i++) {
let sliderBar = document.querySelector(`.slider${i} .el-slider__bar`) as HTMLElement
let sliderButton = document.querySelector(`.slider${i} .el-slider__button`) as HTMLElement
// 循环预设颜色数组
let index = i
if (i >= sliderBarColors.length) {
index = i % sliderBarColors.length
}
sliderBar.style.background = sliderBarColors[index]
sliderButton.style.borderColor = sliderButtonColors[index]
sliderButton.style.setProperty('--slider-color', sliderButtonColors[index])
}
}
onMounted(() => {
computedBarColor()
})
</script>
<style scoped lang="less">
.progress-contaioner {
/*声明一个变量*/
--slider-color: #0000;
width: 100%;
height: 100%;
}
:deep(.slider-demo-block .el-slider) {
margin-top: 0.44rem;
margin-bottom: 1.63rem;
height: 0.25rem;
/* 滑动条颜色 */
.el-slider__bar {
// background: linear-gradient(270deg, #ff9c12 0%, rgba(253, 114, 25, 0.32) 100%);
border-radius: 0.13rem;
}
/* 滑块颜色 */
.el-slider__button {
// border-color: #ff9c12;
background: rgba(79, 49, 7, 0.48);
&:after {
content: '';
display: block;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 7px;
height: 7px;
border-radius: 50%;
background: var(--slider-color);
}
}
/* 滑动轨颜色 */
.el-slider__runway {
background-color: rgba(47, 47, 47, 0.6);
}
}
.progress-info {
display: flex;
justify-content: space-between;
color: #ffffff;
font-size: 0.75rem;
}
.proportion-maximums {
color: rgba(255, 255, 255, 0.5);
}
.proportion-unit {
font-size: 0.5rem;
margin-left: 0.25rem;
}
</style>
父组件调用的时候记得把数组传过去就行了:
<progress-bar :progressList="progressList"></progress-bar>