自定义的canvas组件
summaryDialog.vue
<template> <Theme> <!-- default 必须加 --> <template #center> <view class="dialog-mask"> <view class="content"> <view class="summary-dialog"> <view class="top-score"> <canvas style="width: 84px; height: 84px" canvas-id="circlefCanvas" ></canvas> <text class="score-text">得分</text> </view> <view class="center-contain"> <view class="num-item"> <view class="num total-color">{{data.total}}题</view> <view class="sub-text">总题数</view> </view> <view class="num-item"> <view class="num right-color">{{data.right}}题</view> <view class="sub-text">正确</view> </view> <view class="num-item"> <view class="num error-color">{{data.total - data.right}}题</view> <view class="sub-text">错误</view> </view> </view> <view class="score-foot-btns"> <view class="btn left" @click="close()">取消</view> <view class="btn right" @click="confirm()">确定</view> </view> </view> </view> </view> </template> </Theme> </template> <script setup lang="ts"> import { onReady } from "@dcloudio/uni-app"; import { onMounted, getCurrentInstance } from "vue"; interface Props { data: { [key: string]: number } } const props = withDefaults(defineProps<Props>(), { data: function() { return { right: 8, score: 80, total: 10 } } }) const emit = defineEmits(["close", "confirm"]); const close = () => { emit("close", "close"); }; const confirm = () => { emit("confirm", "confirm"); }; /** * 环形进度条 * arc(x, y, r, startAngle, endAngle, anticlockwise): * 以(x, y) 为圆心,以r 为半径,90°代表0.5 * PI * 从 startAngle 弧度开始到endAngle弧度结束。 * anticlosewise 是布尔值,true 表示逆时针,false 表示顺时针(默认是顺时针 */ const circleProgressbar = (score: number, value: number) => { const instance = getCurrentInstance() as any // 换整个圆环 const ctx = uni.createCanvasContext("circlefCanvas", instance); ctx.beginPath(); ctx.arc(42, 42, 30, 0, 2 * Math.PI); ctx.setStrokeStyle("#FAF7F7"); ctx.setLineWidth(5); ctx.stroke(); // 进度 ctx.beginPath(); ctx.arc(42, 42, 30, 0, value * Math.PI); ctx.setStrokeStyle("#E8736F"); ctx.setLineWidth(5); ctx.stroke(); // 中心字体 ctx.setFillStyle("#E8736F"); ctx.setFontSize(17); ctx.setTextAlign("center"); ctx.fillText(`${score}分`, 42, 50); ctx.stroke(); ctx.draw(); }; onMounted(() => { const percent = (props.data?.score / 100) * 2 circleProgressbar(props.data?.score, percent); }); </script> <style lang="scss"> .dialog-mask { opacity: 1; position: fixed; inset: 0px; background-color: rgba(0, 0, 0, 0.4); transition: opacity 300ms ease 0ms, -webkit-transform 300ms ease 0ms, transform 300ms ease 0ms; transform-origin: 50% 50%; .content { transform: scale(1); opacity: 1; position: fixed; display: flex; flex-direction: column; inset: 0px; justify-content: center; align-items: center; transition: opacity 300ms ease 0ms, -webkit-transform 300ms ease 0ms, transform 300ms ease 0ms; transform-origin: 50% 50%; } .summary-dialog { width: 80%; height: 50%; display: flex; flex-direction: column; justify-content: space-between; background: #ffffff; border-radius: 12rpx; padding: 30rpx; .top-score { display: flex; flex-direction: column; // justify-content: center; align-items: center; margin: 30rpx; .score-text { font-weight: bold; font-size: 34rpx; color: #000000; } } .center-contain { background: #faf7f7; border-radius: 8rpx; margin: 30rpx 0px; height: 136rpx; display: flex; .num-item { width: 33.33%; display: flex; flex-direction: column; align-items: center; justify-content: center; .num { font-size: 14px; font-weight: bold; } .sub-text { font-weight: 500; color: #8d8d8d; font-size: 13px; } .total-color { color: $uni-main-color; } .right-color { color: #F33A52; } .error-color { color: #07C180; } } } .score-foot-btns { display: flex; justify-content: space-between; .btn { width: 40%; display: flex; justify-content: center; align-items: center; height: 80rpx; font-size: 17px; font-weight: bold; border-radius: 12rpx; } .left { color: $uni-base-color; border: 2rpx solid $uni-base-color; } .right { color: white; background-color: $uni-primary; } } } } </style>
import SummaryDialog from './dialog/summaryDialog.vue' ..... <view> <SummaryDialog v-if="summaryDialogVisible" @close="close" @confirm="confirm"></SummaryDialog> </view>
我遇到的情况