【前端】【css】拱形实现

项目场景:

提示:这里简述项目相关背景:

鸿图H5-报告页面-实现拱形
在这里插入图片描述


实现

组件

<template>
  <div class="score-arch">
    <div class="arch-wrapper">
      <svg viewBox="0 0 200 200">
        <!-- 背景环 -->
        <path :d="arcPath" stroke="#FFF4F3" stroke-width="22" fill="none" />
        <path :d="arcPath" stroke="#FFE0DD" stroke-width="10" fill="none" />

        <!-- 进度环 -->
        <path
            :d="arcPath"
            stroke="url(#grad)"
            stroke-width="10"
            fill="none"
            :stroke-dasharray="`${progressLength}, ${totalLength}`"
            stroke-dashoffset="0"
        />

        <!-- 渐变定义 -->
        <defs>
          <linearGradient id="grad" x1="0" y1="0" x2="1" y2="1">
            <stop offset="0%" stop-color="#ff6034" />
            <stop offset="100%" stop-color="#ee0a24" />
          </linearGradient>
        </defs>

        <!-- 末端小圆点 -->
        <circle
            :cx="endX"
            :cy="endY"
            r="6.5"
            fill="#fff"
            stroke-width="3"
            style="filter: drop-shadow(0 0 4px rgba(0,0,0,0.15));"
        />
      </svg>

      <!-- 中间得分文案 -->
      <div class="score-text">
        <p class="label">答对</p>
        <p class="value">
          <span class="score-value">{{ value }}</span>/<span>{{ max }}</span>
        </p>
        <p class="score" v-if="score">得分 {{ score }} / {{ totalScore }}</p>
      </div>
    </div>
  </div>
</template>

<script setup>
import { computed } from 'vue'

/**
 * Props
 * value: 当前值
 * max: 最大值
 * score: 当前得分
 * totalScore: 总分
 * radius: 圆弧半径(默认83)
 */
const props = defineProps({
  value: { type: Number, default: 10 },
  max: { type: Number, default: 100 },
  score: { type: Number, default: 0 },
  totalScore: { type: Number, default: 100 },
  radius: { type: Number, default: 83 },
})

/**
 * 缺口大小控制
 * 这里我们去掉下方 1/4 的圆弧 => 总角度 270°
 * 起始角度 135°,结束角度 405°
 */
const startAngle = (135 * Math.PI) / 180
const endAngle = (405 * Math.PI) / 180

// SVG 路径
const arcPath = computed(() => {
  const r = props.radius
  const cx = 100
  const cy = 100
  const startX = cx + r * Math.cos(startAngle)
  const startY = cy + r * Math.sin(startAngle)
  const endX = cx + r * Math.cos(endAngle)
  const endY = cy + r * Math.sin(endAngle)
  return `M ${startX},${startY} A ${r},${r} 0 1 1 ${endX},${endY}`
})

// 总长度(弧长)
const totalLength = computed(() => props.radius * Math.PI * (270 / 180))

// 当前进度长度
const progressLength = computed(() => {
  const rate = Math.min(props.value / props.max, 1)
  return totalLength.value * rate
})

// 终点坐标
const endX = computed(() => {
  const r = props.radius
  const rate = Math.min(props.value / props.max, 1)
  const angle = startAngle + (endAngle - startAngle) * rate
  const cx = 100
  return cx + r * Math.cos(angle)
})

const endY = computed(() => {
  const r = props.radius
  const rate = Math.min(props.value / props.max, 1)
  const angle = startAngle + (endAngle - startAngle) * rate
  const cy = 100
  return cy + r * Math.sin(angle)
})
</script>

<style scoped lang="scss">
.score-arch {
  background: #fff;
  width: 21.4375rem;
  height: 13.875rem;
  border-radius: 0.5rem;
  padding: 1.5rem 1rem 1rem;
  text-align: center;
  margin: 2rem auto;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}

.arch-wrapper {
  position: relative;
  width: 11.25rem;
  margin: 0 auto;
}

.score-text {
  position: absolute;
  top: 25%;
  left: 0;
  right: 0;
  text-align: center;
  line-height: 1.4;

  .label {
    font-size: 0.85rem;
    color: #888;
  }
  .value {
    font-size: 1rem;
    color: #333333;
    .score-value {
      color: #FA2C19;
      font-size: 2.25rem;
      font-weight: 600;
    }
  }
  .score {
    font-size: 0.9rem;
    color: #666;
  }
}
</style>


调用

<template>
  <div class="report-page">
    <div class="header-bg">...</div>

    <!-- 使用组件 -->
    <ScoreArch
        :value="report.correct"
        :max="report.total"
        :score="report.score"
        :totalScore="report.totalScore"
    />

    <!-- 其他内容 -->
  </div>
</template>

<script setup>
import ScoreArch from '~/components/ScoreArch.vue'
const report = reactive({
  correct:5,
  total:20,
  score:5,
  totalScore:100,
})
</script>

实现结果

在这里插入图片描述
在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值