1. 程式人生 > 其它 >uniapp微信小程式端canvas做為自定義元件引入使用時不顯示問題的解決方法

uniapp微信小程式端canvas做為自定義元件引入使用時不顯示問題的解決方法

環境
  • uniapp(vue3)
  • vite
問題描述
  • 把canvas放在自定義元件裡,然後將其迎入到其他元件使用時在微信小程式端不顯示
解決方法(可能造成的原因)
    1. 沒有寫canvas-id
    1. uni.createCanvasContext方法沒有傳入元件例項(單獨作為元件引入時,vue2為this,vue3為getCurrentInstance())
    1. canvas標籤上寫了type="2d"(單獨作為元件引入時)
  • 4.沒有在onReady或者onMounted生命週期裡實列話canvas

程式碼

自定義的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>

結果

我遇到的情況

  • 沒加type="2d"時正常
  • 加了type="2d"時canvas不顯示