跳转到内容

比例分隔条

Demo

@ep_src_vue_generic_component_proportional_split_bar_Example1(./Example1.vue)
vue
<script setup lang="ts">
import ProportionalSplitBar from './ProportionalSplitBar.vue'
</script>

<template>
  <div style="display: flex; flex-direction: column; gap: 20px">
    <ProportionalSplitBar :proportional="[7500, 12500]"  />
    <ProportionalSplitBar :proportional="[0, 0]"  />
    <ProportionalSplitBar :proportional="[630, 500]" :decimal="2" />
    <ProportionalSplitBar :left-value="75" style="--divider-angle: 15deg;" />
    <ProportionalSplitBar :left-value="75" style="--divider-angle: 0deg;" />
    <ProportionalSplitBar
      :left-value="75"
      style="
        --left-bg: linear-gradient(180deg, #3677ff 0%, #52e5e7 100%);
        --right-bg: linear-gradient(180deg, #0e5cad 0%, #79f1a4 100%);
      "
    />
    <ProportionalSplitBar
      :left-value="75"
      style="--height: 36px; --font-size: 16px"
    />
  </div>
</template>

组件代码

vue
<script setup lang="ts">
import { computed } from 'vue'

interface Props {
  proportional?: [number, number]
  leftValue?: number // 0 - 100
  decimal?: number
}
const props = withDefaults(defineProps<Props>(), {
  leftValue: 0,
})

const values = computed<[number, number, number]>(() => {
  if (props.proportional) {
    const numbers = props.proportional.map(Number)
    const sum = numbers[0] + numbers[1]
    if (sum === 0) {
      return [0, 0, 50]
    }
    return [
      (numbers[0] / sum) * 100,
      (numbers[1] / sum) * 100,
      (numbers[0] / sum) * 100,
    ]
  } else {
    return [props.leftValue, 100 - props.leftValue, props.leftValue]
  }
})
</script>

<template>
  <div
    class="proportional-split-bar"
    :style="{ '--left-value': values[2] }"
  >
    <div class="side left">
      <div class="side-text">{{ values[0].toFixed(decimal) }}%</div>
    </div>
    <div class="divider"></div>
    <div class="side right">
      <div class="side-text">{{ values[1].toFixed(decimal) }}%</div>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.proportional-split-bar {
  --left-value: 0;
  --height: 56px;
  --side-width: 110px;
  --left-bg: linear-gradient(180deg, #ea5455 0%, #feb692 100%);
  --right-bg: linear-gradient(180deg, #7367f0 0%, #ce9ffc 100%);
  --font-size: 24px;
  --divider-width: 6px;
  --divider-angle: -15deg;
  --side-padding: 15px;

  position: relative;
  height: var(--height);
  min-width: calc(var(--side-width) * 2);
  border-radius: 10px;
  overflow: hidden;
  &::before {
    content: '';
    position: absolute;
    top: 0;
    left: calc(0px - var(--height));
    z-index: 2;
    width: calc(
      (100% - (var(--side-width) * 2)) * (var(--left-value) / 100) +
        var(--side-width) + var(--height)
    );
    height: var(--height);
    background: var(--left-bg);
    transform: skewX(var(--divider-angle));
  }
  &::after {
    content: '';
    position: absolute;
    top: 0;
    right: 0;
    z-index: 1;
    width: 100%;
    height: var(--height);
    background: var(--right-bg);
  }
  .side {
    width: var(--side-width);
    height: var(--height);
    position: absolute;
    top: 0;
    display: flex;
    align-items: center;

    &.left {
      justify-content: flex-start;
      left: 0;
      z-index: 4;
      padding-left: var(--side-padding);
    }
    &.right {
      justify-content: flex-end;
      right: 0;
      z-index: 2;
      padding-right: var(--side-padding);
    }
  }
  .side-text {
    font-family: D-DIN, D-DIN;
    font-weight: 700;
    font-size: var(--font-size);
    color: #ffffff;
    line-height: var(--font-size);
    height: var(--font-size);
    text-align: left;
    font-style: normal;
    text-transform: none;
    .unit {
      font-size: var(--unit-font-size);
    }
  }
  .divider {
    position: absolute;
    top: 0;
    left: calc(
      (100% - (var(--side-width) * 2)) * (var(--left-value) / 100) +
        var(--side-width)
    );
    width: var(--divider-width);
    height: 100%;
    transform: translateX(-50%) skewX(var(--divider-angle));
    background-color: #fff;
    z-index: 5;
  }
}
</style>

说明

  • --side-width 取值:最好大于某一侧文字为 100% 时所占宽度+内边距