Vue3 基于Element Plus 线型进度条 el-progress 二次封装

项目背景

ui设计师在设计线型进度条的时候在进度条底部加上了一个显示数据的面板,但是Element Plus提供的format和slot不满足此次的需求,就自己封装了一下。

Vue3 基于Element Plus 线型进度条 el-progress 二次封装_第1张图片

代码

<template>
    <div class="progress">
        <el-progress :percentage="progressNumber" :show-text="showTextFn" />
        <div ref="panel" v-show="showPlan" class="panel">{{ planTextStr }}div>
    div>
template>
<script lang="ts" setup>
import { computed, ref, onMounted, watch } from 'vue';
const props = defineProps({
    // 百分比,必填 0-100
    percentage: {
        type: Number,
        default() {
            return 0
        }
    },
    // 进度条类型
    type: {
        type: String,
        default() {
            return 'line' // line/circle/dashboard
        }
    },
    // stroke-width
    strokeWidth: {
        type: Number,
        default() {
            return 6
        }
    },
    // 是否显示进度条文字内容
    showText: {
        type: Boolean,
        default() {
            return true
        }
    },
    // 是否显示信息面板
    showPlan: {
        type: Boolean,
        default() {
            return false
        }
    },
    // 面板显示文字
    planText: String,
})

const progressNumber = computed(() => {
    if (props.percentage > 100) return 100;
    else if (props.percentage < 0) return 0;
    else return props.percentage;
})

const showTextFn = computed(() => {
    if (props.showPlan) return false
    return props.showText
})

const panel = ref<any>(null);
const panelHeight = ref<string>('0px');
const translateX = ref<string>('0%');
const left = computed(() => `${progressNumber.value}%`);

const planTextStr = computed(() => {
    if (props.planText) return props.planText;
    else return `${progressNumber.value}%`
})

const showPlanType = computed(() => {
    if (props.type === 'line') return props.showPlan;
    else return false
})

onMounted(() => {
    if (showPlanType.value) {
        panelHeight.value = `${panel.value.offsetHeight + 5}px`;
        const widthHalf = panel.value.offsetWidth / 2; // 面板宽度的一半
        if (progressNumber.value > widthHalf && progressNumber.value < (100 - widthHalf)) translateX.value = '-50%';
        else  translateX.value = '0%';
    }
})
// 监听百分比变化 修改面板translateX
watch(
    progressNumber,
    (val, preVal) => {
        if (!showPlanType.value) return
        const widthHalf = panel.value.offsetWidth / 2; // 面板宽度的一半
        if (progressNumber.value > widthHalf && progressNumber.value < (100 - widthHalf)) translateX.value = '-50%';
        else if (progressNumber.value >= (100 - widthHalf)) translateX.value = '-100%';
        else  translateX.value = '0%';
    }
)

</script>
.progress {
    position: relative;
}

.progress::after {
    content: '';
    display: inline-block;
    height: v-bind(panelHeight);;
}

.progress .panel {
    max-width: 100%;
    white-space: nowrap;/*内容超宽后禁止换行显示*/
    overflow: hidden;/*超出部分隐藏*/
    text-overflow:ellipsis;/*文字超出部分以省略号显示*/
    position: absolute;
    left: v-bind(left);
    bottom: 0;
    z-index: 1;
    background: #EAEDF4;
    border-radius: 4px;
    padding: 0 6px;
    height: 22px;
    line-height: 22px;
    white-space: nowrap;
    transform: translateX(v-bind(translateX));
    transition: all .5s;
}

你可能感兴趣的:(JavaScript,vue,vue.js,javascript,前端)