Browse Source

feat: countup、barrage、signature 单元测试 (#1084)

Ymm0008 3 years ago
parent
commit
200634ee97

+ 1 - 0
package.json

@@ -82,6 +82,7 @@
     "@vue/test-utils": "^2.0.0-rc.18",
     "autoprefixer": "^10.3.4",
     "axios": "^0.21.0",
+    "canvas": "^2.9.0",
     "eslint": "^7.23.2",
     "eslint-plugin-prettier": "^3.3.1",
     "eslint-plugin-vue": "^7.8.0",

+ 78 - 0
src/packages/__VUE/barrage/__tests__/barrage.spec.ts

@@ -0,0 +1,78 @@
+import { config, mount } from '@vue/test-utils';
+import Barrage from '../index.vue';
+import { nextTick, ref } from 'vue';
+function sleep(delay = 0): Promise<void> {
+  return new Promise((resolve) => {
+    setTimeout(resolve, delay);
+  });
+}
+// 所有的测试用例之前执行一次
+beforeAll(() => {
+  config.global.components = {
+    NutBarrage: Barrage
+  };
+});
+// 所有的测试用例之后执行一次
+afterAll(() => {
+  config.global.components = {};
+});
+test('should danmu list props', async () => {
+  const wrapper = mount({
+    template: `<nut-barrage ref="danmu" :danmu="list" :speeds="speeds"></nut-barrage>`,
+    setup() {
+      const danmu = ref(null);
+      const list = ref(['画美不看', '不明觉厉', '喜大普奔', '男默女泪', '累觉不爱', '爷青结']);
+      const speeds = ref(300);
+      return {
+        list,
+        danmu,
+        speeds
+      };
+    }
+  });
+  await nextTick();
+  await sleep(4000);
+  const danmuList = wrapper.findAll('.dmitem');
+  danmuList.forEach((item) => {
+    expect(Number(item.attributes('data-index'))).toBeLessThan(wrapper.vm.list.length);
+  });
+  const ele = danmuList[0].element as HTMLElement;
+  expect(ele.style.animationDuration).toEqual(`${wrapper.vm.speeds}ms`);
+});
+
+test('should danmu rows top', async () => {
+  const wrapper = mount({
+    template: `<nut-barrage ref="danmu" :danmu="list" :rows="rows" :top="top"></nut-barrage>`,
+    setup() {
+      const danmu: any = ref(null);
+      const list = ref(['画美不看', '不明觉厉', '喜大普奔', '男默女泪', '累觉不爱', '爷青结']);
+      const rows = ref(3);
+      const top = ref(30);
+      const addDanmu = () => {
+        const n: number = Math.random();
+        danmu.value.add('随机——' + String(n).substr(2, 10));
+      };
+      return {
+        list,
+        danmu,
+        rows,
+        top,
+        addDanmu
+      };
+    }
+  });
+  await nextTick();
+  wrapper.vm.addDanmu();
+  await sleep(4500);
+  const danmuList = wrapper.findAll('.dmitem');
+  const ele = danmuList[1].element as HTMLElement;
+  const top = parseFloat(ele.style.top);
+  expect(top - 26 + 6).toBe(wrapper.vm.top);
+  // const danmuitem = danmuList.filter(item => Number(item.attributes('data-index')) >= wrapper.vm.list.length);
+  danmuList.forEach((item) => {
+    if (Number(item.attributes('data-index')) + 1 >= wrapper.vm.list.length) {
+      const idx = Number(item.attributes('data-index'));
+      expect(idx).toBe(wrapper.vm.list.length - 1);
+    }
+  });
+});

+ 195 - 0
src/packages/__VUE/countup/__test__/countup.spec.ts

@@ -0,0 +1,195 @@
+import { config, mount } from '@vue/test-utils';
+import Countup from '../index.vue';
+import { nextTick, reactive, ref, toRefs } from 'vue';
+function sleep(delay = 0): Promise<void> {
+  return new Promise((resolve) => {
+    setTimeout(resolve, delay);
+  });
+}
+
+// 所有的测试用例之前执行一次
+beforeAll(() => {
+  config.global.components = {
+    NutCountup: Countup
+  };
+});
+// 所有的测试用例之后执行一次
+afterAll(() => {
+  config.global.components = {};
+});
+test('basic usage props init-num end-num speed', async () => {
+  const component = {
+    template: `<nut-countup :init-num="initNum" :end-num="endNum" :speed="speed"></nut-countup>`,
+    setup() {
+      const data = reactive({
+        initNum: 0,
+        endNum: 4,
+        speed: 3
+      });
+      return {
+        ...toRefs(data)
+      };
+    }
+  };
+  const wrapper = mount(component);
+  const countupWrapper = wrapper.find('.nut-countup').element as Element;
+  await nextTick();
+  expect(countupWrapper.textContent).toBe(wrapper.vm.initNum + '');
+
+  await sleep(1000);
+  const cur = countupWrapper.textContent;
+  const differenceNum = Number(cur) - wrapper.vm.initNum;
+  expect(differenceNum % wrapper.vm.speed).toBe(0);
+
+  await sleep(3000);
+  expect(countupWrapper.textContent).toBe(wrapper.vm.endNum + '');
+});
+
+test('basic usage props decimal places', async () => {
+  const component = {
+    template: `<nut-countup :init-num="200" :end-num="0" :speed="6.18" :to-fixed="toFixed"></nut-countup>`,
+    setup() {
+      const data = reactive({
+        toFixed: 2
+      });
+      return {
+        ...toRefs(data)
+      };
+    }
+  };
+  const wrapper = mount(component);
+  await nextTick();
+  const countupWrapper = wrapper.find('.nut-countup').element as Element;
+  await sleep(4000);
+  const num = countupWrapper.textContent;
+  const len = num?.toString().split('.')[1];
+  expect(len?.length).toBe(wrapper.vm.toFixed);
+});
+
+test('digital scrolling during props', async () => {
+  const component = {
+    template: `<nut-countup
+      :scrolling="true"
+      :init-num='17.618'
+      :num-width="numWidth"
+      :num-height="numHeight"
+      :during="during"
+    ></nut-countup>`,
+    setup() {
+      const data = reactive({
+        during: 600,
+        numWidth: 30,
+        numHeight: 30
+      });
+      return {
+        ...toRefs(data)
+      };
+    }
+  };
+  const wrapper = mount(component);
+  await nextTick();
+  await sleep(1000);
+
+  expect(wrapper.findAll('.run-number')).toHaveLength(1);
+
+  const numberItemList = wrapper.findAll('.numberItem');
+  const numItem = numberItemList[numberItemList.length - 1].element as HTMLElement;
+  expect(numItem.style.transition).toEqual(`all linear ${wrapper.vm.during}ms`);
+
+  const itemSpan = wrapper.find('.itemSpan').element as HTMLElement;
+  expect(itemSpan.style.width).toBe(`${wrapper.vm.numWidth}px`);
+  expect(itemSpan.style.height).toBe(`${wrapper.vm.numHeight}px`);
+});
+
+test('custom img size props', async () => {
+  const component = {
+    template: `<nut-countup
+      :custom="true"
+      :num-height="numHeight"
+      :custom-change-num="customChangeNum"
+      :custom-bg-img='customBgImg'
+      :custom-spac-num="customSpaceNum"
+    ></nut-countup>`,
+    setup() {
+      const data = reactive({
+        numHeight: 47,
+        customChangeNum: 618,
+        customBgImg:
+          'https://img10.360buyimg.com/imagetools/jfs/t1/121466/20/6784/28830/5f06e7f2Edbb8998c/9bdd9e7b24dff9fe.png',
+        customSpaceNum: 5
+      });
+      return {
+        ...toRefs(data)
+      };
+    }
+  };
+  const wrapper = mount(component);
+  await nextTick();
+  await sleep(2000);
+  const numberItemList = wrapper.findAll('.run-number-img-li');
+  const ele = numberItemList[0].element as HTMLElement;
+  const _y = Math.abs(parseFloat(ele.style.backgroundPositionY));
+  const _num = Number(String(wrapper.vm.customChangeNum).charAt(0));
+  const __y = _num * wrapper.vm.numHeight + wrapper.vm.customSpaceNum * _num;
+  expect(_y).toBe(__y);
+});
+
+test('game machine props', async () => {
+  const component = {
+    template: `<nut-countup
+      ref="countupMachineDom"
+      type="machine"
+      :machine-num="machineNum"
+      :machine-prize-num="machinePrizeNum"
+      :machine-prize-level="machinePrizeLevel"
+      :machine-trun-more="machineTrunMore"
+      :custom-bg-img="bgImage"
+      :num-width="100"
+      :num-height="100"
+      :during="2000"
+      @scroll-end="scrollAniEnd"
+    ></nut-countup>`,
+    setup() {
+      const countupMachineDom: any = ref(null);
+      const data = reactive({
+        machineNum: 3,
+        machinePrizeNum: 5,
+        bgImage:
+          'https://img10.360buyimg.com/imagetools/jfs/t1/121466/20/6784/28830/5f06e7f2Edbb8998c/9bdd9e7b24dff9fe.png',
+        machinePrizeLevel: -1,
+        machineTrunMore: 3,
+        cbFlag: ''
+      });
+      const scrollAniEnd = () => {
+        data.cbFlag = 'end';
+      };
+      const startRole = () => {
+        data.machinePrizeLevel = Math.floor(Math.random() * 5 + 1);
+        countupMachineDom.value.machineLuck();
+      };
+      return {
+        countupMachineDom,
+        ...toRefs(data),
+        startRole,
+        scrollAniEnd
+      };
+    }
+  };
+  const wrapper = mount(component);
+  await nextTick();
+  // await sleep(2000);
+  const machine = wrapper.findAll('.run-number-machine-img');
+  expect(machine).toHaveLength(1);
+  const machineItemList = wrapper.findAll('.run-number-machine-img-li');
+  expect(machineItemList).toHaveLength(wrapper.vm.machineNum);
+  wrapper.vm.startRole();
+  await sleep(4000);
+  const ele = machineItemList[0].element as HTMLElement;
+  const _y = Math.abs(parseFloat(ele.style.backgroundPositionY));
+  const dis = wrapper.vm.machinePrizeNum * parseFloat(ele.style.height) * 2;
+  expect(_y).toBeGreaterThan(dis);
+  const scrollY = (wrapper.vm.machinePrizeNum - wrapper.vm.machinePrizeLevel + 1) * parseFloat(ele.style.height);
+  expect(_y).toBeGreaterThan(scrollY);
+  const circle = wrapper.vm.machineTrunMore * parseFloat(ele.style.height);
+  expect(_y).toBeGreaterThan(circle);
+});

+ 3 - 2
src/packages/__VUE/countup/demo.vue

@@ -4,11 +4,11 @@
     <div class="show-demo">
       <nut-countup :init-num="0" :end-num="200"></nut-countup>
       <nut-countup :init-num="150.0" :end-num="0.0" :speed="6.18" :to-fixed="2"></nut-countup>
-      <nut-countup :init-num="500.0" :end-num="0.0" :speed="17" :to-fixed="2"></nut-countup>
+      <nut-countup :init-num="500.0" :end-num="0.0" :speed="50" :to-fixed="2"></nut-countup>
     </div>
     <h2>数字滚动</h2>
     <div class="show-demo">
-      <nut-countup :scrolling="true" :init-num="18.618" :end-num="18.618" :during="600"></nut-countup>
+      <nut-countup :scrolling="true" :init-num="18.618" :during="600"></nut-countup>
     </div>
     <h2>自定义滚动图片展示</h2>
     <div class="show-demo">
@@ -30,6 +30,7 @@
         :machine-num="machineNum"
         :machine-prize-num="5"
         :machine-prize-level="prizeLevel"
+        :machine-turn-more="5"
         :custom-bg-img="bgImage2"
         :num-width="100"
         :num-height="100"

+ 2 - 2
src/packages/__VUE/countup/doc.md

@@ -27,7 +27,7 @@ app.use(CountUp);
 <template>
     <nut-countup :init-num='0' :end-num='200'></nut-countup>
     <nut-countup :init-num='150.00' :end-num='0.00' :speed='2.62' :to-fixed='2'></nut-countup>
-    <nut-countup :init-num='1000.00' :end-num='0.00' :speed='6.3' :start-flag='startNum' :to-fixed='2'></nut-countup>
+    <nut-countup :init-num='1000.00' :end-num='0.00' :speed='50' :to-fixed='2'></nut-countup>
 </template>
 ```
 
@@ -163,7 +163,7 @@ export default {
 | machine-prize-num | 奖品个数,一共多少个奖品,必传 | number | 4
 | machine-num | 抽奖位,即滚动几个,必传 | number | 3
 | machine-prize-level | 中奖图标,图标在雪碧图中的位置 | number | 0
-| machine-trun-more | 滚动圈数 | number | 0
+| machine-turn-more | 滚动圈数 | number | 0
 
 > 说明:抽奖功能需要结合图标位置计算,故需传入雪碧图中单个图标的高度 num-height;中奖奖品根据雪碧图中的奖品位数来定位,从 1 到 N;
 

+ 34 - 16
src/packages/__VUE/countup/index.vue

@@ -19,7 +19,7 @@
         </view>
       </template>
       <template v-else>
-        <view class="run-number-img" :style="{ height: numHeight + 'px' }">
+        <view ref="runNumberImg" class="run-number-img" :style="{ height: numHeight + 'px' }">
           <view
             class="run-number-img-li"
             v-for="(val, index) of num_total_len"
@@ -36,8 +36,10 @@
                     : index) +
                 'px',
               backgroundImage: 'url(' + customBgImg + ')',
-              backgroundPosition:
-                '0 ' + -(String(relNum)[index] * numHeight + customSpacNum * String(relNum)[index]) + 'px',
+              backgroundPositionX: '0',
+              backgroundPositionY: -(String(relNum)[index] * numHeight + customSpacNum * String(relNum)[index]) + 'px',
+              // backgroundPosition:
+              //   '0 ' + -(String(relNum)[index] * numHeight + customSpacNum * String(relNum)[index]) + 'px',
               transition: 'all linear ' + during / 10 + 'ms'
             }"
           ></view>
@@ -66,7 +68,7 @@
         }"
       >
         <view
-          ref="numberItem"
+          :ref="setRef"
           class="numberItem"
           v-for="(val, index) of num_total_len"
           :key="val"
@@ -116,7 +118,7 @@ const { componentName, create } = createComponent('countup');
 
 interface IData {
   valFlag: boolean;
-  current: number;
+  current: number | string;
   sortFlag: string;
   initDigit1: number;
   initDigit2: number;
@@ -207,7 +209,7 @@ export default create({
       type: Number,
       default: 0
     },
-    machineTrunMore: {
+    machineTurnMore: {
       type: Number,
       default: 0
     }
@@ -215,6 +217,11 @@ export default create({
   components: {},
   emits: ['click', 'scroll-end'],
   setup(props, { emit }) {
+    const runNumberImg = ref(null);
+    const numberItemRef = ref<any>([]);
+    const setRef = (el: Element) => {
+      numberItemRef.value.push(el);
+    };
     const data: IData = reactive({
       valFlag: false,
       current: 0,
@@ -346,22 +353,24 @@ export default create({
           //减少
           if (data.current <= endNum || data.current <= speed) {
             //数字减小,有可能导致current小于speed
-            data.current = Number(endNum.toFixed(toFixed));
+            data.current = endNum.toFixed(toFixed);
             clearInterval(countTimer);
             emit('scroll-end');
             data.valFlag = false;
           } else {
-            data.current = Number((parseFloat(String(data.current)) - parseFloat(String(speed))).toFixed(toFixed));
+            let num = parseFloat(String(data.current)) - parseFloat(String(speed));
+            data.current = num.toFixed(toFixed);
           }
         } else {
           //增加
           if (data.current >= endNum) {
-            data.current = Number(endNum.toFixed(toFixed));
+            data.current = endNum.toFixed(toFixed);
             clearInterval(countTimer);
             emit('scroll-end');
             data.valFlag = false;
           } else {
-            data.current = Number((parseFloat(String(data.current)) + parseFloat(String(speed))).toFixed(toFixed));
+            let num = parseFloat(String(data.current)) + parseFloat(String(speed));
+            data.current = num.toFixed(toFixed);
           }
         }
       }, props.during);
@@ -453,8 +462,8 @@ export default create({
           if (data.sortFlag == 'equal') {
             return false;
           }
-          let refsDom: HTMLCollectionOf<Element> = document.getElementsByClassName('numberItem');
-          let element = refsDom[data.num_total_len - 1];
+          // let refsDom: any = document.getElementsByClassName('numberItem');
+          let element = numberItemRef.value[data.num_total_len - 1];
           runTurn(element);
         });
       } else {
@@ -484,6 +493,13 @@ export default create({
 
     const runStep = (el: any) => {
       let currentTurn = el.getAttribute('turn-number');
+      // try {
+      //   currentTurn = el.getAttribute('turn-number');
+      // } catch (e) {
+      //   let _top = el.style.top.replace(/\-|\%/g, '');
+      //   let n = 10 - Number(_top) / 100;
+      //   currentTurn = n;
+      // }
       let turningNum: number;
       if (data.sortFlag == 'add') {
         turningNum = parseInt(String(currentTurn)) + 1;
@@ -526,11 +542,11 @@ export default create({
         m = Math.pow(10, data.pointNum);
       }
       nextTick(() => {
-        let f = document.getElementsByClassName('run-number-img')[0];
+        // var f = document.getElementsByClassName('run-number-img')[0];
         // setTimeout(() => {
         //   data.relNum = calculation(data.relNum, m * props.speed, '+');
         // }, props.during);
-        f.addEventListener('webkitTransitionEnd', () => {
+        (runNumberImg.value as any).addEventListener('webkitTransitionEnd', () => {
           emit('scroll-end');
           data.valFlag = false;
           // setTimeout(() => {
@@ -551,14 +567,14 @@ export default create({
     };
     // 抽奖
     const machineLuck = () => {
-      const machineTrunMoreNum = props.machineTrunMore < 0 ? 0 : props.machineTrunMore;
+      const machineTurnMoreNum = props.machineTurnMore < 0 ? 0 : props.machineTurnMore;
       let distance = props.numHeight * props.machinePrizeNum; // 所有奖品的高度,雪碧图的高度
       if (data.prizeLevelTrun < 0) {
         generateRandom();
       }
       for (let i = 0; i < props.machineNum; i++) {
         setTimeout(() => {
-          let turn = distance * (i + 1 + parseFloat(String(machineTrunMoreNum)));
+          let turn = distance * (i + 1 + parseFloat(String(machineTurnMoreNum)));
           if (data.prizeYPrev.length != 0) {
             // this.machineTransition = 'none';
             // console.log(this.prizeYPrev[i]-(this.numHeight * this.machinePrizeNum));
@@ -644,6 +660,8 @@ export default create({
     return {
       ...toRefs(data),
       ...toRefs(reactive(props)),
+      runNumberImg,
+      setRef,
       topNumber,
       turnNumber
     };

+ 21 - 0
src/packages/__VUE/signature/__tests__/__snapshots__/signature.spec.ts.snap

@@ -0,0 +1,21 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`props custom-class 1`] = `
+"<div class=\\"nut-signature test\\">
+  <div class=\\"nut-signature-inner\\"><canvas height=\\"0\\" width=\\"0\\"></canvas></div>
+  <view class=\\"nut-button nut-button--default nut-button--normal nut-button--round nut-signature-btn\\">
+    <view class=\\"nut-button__warp\\">
+      <!--v-if-->
+      <!--v-if-->
+      <view class=\\"\\">重签</view>
+    </view>
+  </view>
+  <view class=\\"nut-button nut-button--primary nut-button--normal nut-button--round nut-signature-btn\\">
+    <view class=\\"nut-button__warp\\">
+      <!--v-if-->
+      <!--v-if-->
+      <view class=\\"\\">确认</view>
+    </view>
+  </view>
+</div>"
+`;

+ 57 - 0
src/packages/__VUE/signature/__tests__/signature.spec.ts

@@ -0,0 +1,57 @@
+import { mount, config } from '@vue/test-utils';
+import Signature from '../index.vue';
+import NutIcon from '../../icon/index.vue';
+import NutButton from '../../button/index.vue';
+import { nextTick, reactive, toRefs } from 'vue';
+import { createCanvas, loadImage } from 'canvas';
+
+function sleep(delay = 0): Promise<void> {
+  return new Promise((resolve) => {
+    setTimeout(resolve, delay);
+  });
+}
+// 所有的测试用例之前执行一次
+beforeAll(() => {
+  config.global.components = {
+    NutSignature: Signature,
+    NutIcon,
+    NutButton
+  };
+});
+// 所有的测试用例之后执行一次
+afterAll(() => {
+  config.global.components = {};
+});
+
+test('props custom-class', async () => {
+  const component = {
+    template: `<nut-signature :custom-class="customClass" :line-width="lineWidth" :stroke-style="strokeStyle"></nut-signature>`,
+    setup() {
+      const data = reactive({
+        customClass: 'test',
+        lineWidth: 5,
+        strokeStyle: '#333'
+      });
+      return {
+        ...toRefs(data)
+      };
+    }
+  };
+  const wrapper = mount(component);
+  await nextTick();
+  const signatureWrapper = wrapper.findAll('.nut-signature');
+  expect(signatureWrapper[0].classes()).toContain(wrapper.vm.customClass);
+
+  const canvas = createCanvas(200, 200);
+  const ctx = canvas.getContext('2d');
+  ctx.lineWidth = wrapper.vm.lineWidth;
+  ctx.strokeStyle = wrapper.vm.strokeStyle;
+  ctx.beginPath();
+  ctx.lineTo(10, 50);
+  ctx.lineTo(80, 120);
+  ctx.stroke();
+  const _img = document.createElement('img');
+  _img.src = canvas.toDataURL();
+  expect(canvas.toDataURL()).not.toBeNull();
+  expect(wrapper.html()).toMatchSnapshot();
+});

+ 2 - 5
src/packages/__VUE/signature/demo.vue

@@ -2,15 +2,12 @@
   <div class="demo">
     <h2>基础用法</h2>
     <div>
-      <nut-signature @confirm="confirm" @clear="clear"></nut-signature>
+      <nut-signature @confirm="confirm" @clear="clear" custom-class="test"></nut-signature>
       <p class="demo-tips demo1">Tips: 点击确认按钮,下方显示签名图片</p>
     </div>
     <h2>修改颜色和签字粗细</h2>
     <div>
-      <nut-signature
-        :lineWidth="lineWidth"
-        :strokeStyle="strokeStyle"
-      ></nut-signature>
+      <nut-signature :lineWidth="lineWidth" :strokeStyle="strokeStyle"></nut-signature>
     </div>
   </div>
 </template>

+ 1 - 1
src/packages/__VUE/signature/index.taro.vue

@@ -12,7 +12,7 @@
         @touchmove="moveEventHandler"
         @touchend="endEventHandler"
         @touchleave="leaveEventHandler"
-      />
+      ></canvas>
     </div>
     <nut-button class="nut-signature-btn" type="default" @click="clear()">重签</nut-button>
     <nut-button class="nut-signature-btn" type="primary" @click="confirm()">确认</nut-button>

+ 11 - 28
src/packages/__VUE/signature/index.vue

@@ -1,25 +1,16 @@
 <template>
   <div :class="classes">
     <div class="nut-signature-inner" ref="wrap">
-      <canvas
-        ref="canvas"
-        :height="canvasHeight"
-        :width="canvasWidth"
-        v-if="isCanvasSupported"
-      ></canvas>
+      <canvas ref="canvas" :height="canvasHeight" :width="canvasWidth" v-if="() => isCanvasSupported()"></canvas>
       <p class="nut-signature-unsopport" v-else>{{ unSupportTpl }}</p>
     </div>
 
-    <nut-button class="nut-signature-btn" type="default" @click="clear()"
-      >重签</nut-button
-    >
-    <nut-button class="nut-signature-btn" type="primary" @click="confirm()"
-      >确认</nut-button
-    >
+    <nut-button class="nut-signature-btn" type="default" @click="clear()">重签</nut-button>
+    <nut-button class="nut-signature-btn" type="primary" @click="confirm()">确认</nut-button>
   </div>
 </template>
 <script lang="ts">
-import { ref, reactive, onMounted, computed } from 'vue';
+import { ref, reactive, onMounted, computed, toRefs } from 'vue';
 import { createComponent } from '../../utils/create';
 const { componentName, create } = createComponent('signature');
 
@@ -50,8 +41,8 @@ export default create({
   emits: ['confirm', 'clear'],
 
   setup(props, { emit }) {
-    const canvas = ref<HTMLElement | null>(null);
-    const wrap = ref<HTMLElement | null>(null);
+    const canvas: any = ref<HTMLElement | null>(null);
+    const wrap: any = ref<HTMLElement | null>(null);
     const classes = computed(() => {
       const prefixCls = componentName;
       return {
@@ -59,7 +50,7 @@ export default create({
         [`${props.customClass}`]: props.customClass
       };
     });
-    const state = reactive({
+    const state: any = reactive({
       canvasHeight: 0,
       canvasWidth: 0,
       ctx: null,
@@ -103,20 +94,12 @@ export default create({
     const endEventHandler = (event) => {
       event.preventDefault();
 
-      canvas.value.removeEventListener(
-        state.events[1],
-        moveEventHandler,
-        false
-      );
+      canvas.value.removeEventListener(state.events[1], moveEventHandler, false);
       canvas.value.removeEventListener(state.events[2], endEventHandler, false);
     };
     const leaveEventHandler = (event) => {
       event.preventDefault();
-      canvas.value.removeEventListener(
-        state.events[1],
-        moveEventHandler,
-        false
-      );
+      canvas.value.removeEventListener(state.events[1], moveEventHandler, false);
       canvas.value.removeEventListener(state.events[2], endEventHandler, false);
     };
     const clear = () => {
@@ -140,7 +123,7 @@ export default create({
           dataurl = canvas.toDataURL('image/jpeg', 0.8);
           break;
       }
-      clear(true);
+      clear();
       emit('confirm', canvas, dataurl);
     };
 
@@ -153,7 +136,7 @@ export default create({
       }
     });
 
-    return { canvas, wrap, isCanvasSupported, confirm, clear, classes };
+    return { ...toRefs(state), canvas, wrap, isCanvasSupported, confirm, clear, classes };
   }
 });
 </script>