11<template >
22 <!-- 本体部分 -->
3- <div :id =" id"
4- :class =" ['vue-puzzle-vcode', { show_: show }]"
3+ <div :class =" ['vue-puzzle-vcode', { show_: show }]"
54 @mousedown =" onCloseMouseDown"
65 @mouseup =" onCloseMouseUp"
76 @touchstart =" onCloseMouseDown"
8281<script >
8382import resetSvg from " ./assets/reset.png" ;
8483export default {
85- /** 私有数据 **/
86- data () {
87- return {
88- mouseDown: false , // 鼠标是否在按钮上按下
89- startWidth: 50 , // 鼠标点下去时父级的width
90- startX: 0 , // 鼠标按下时的X
91- newX: 0 , // 鼠标当前的偏移X
92- pinX: 0 , // 拼图的起始X
93- pinY: 0 , // 拼图的起始Y
94- loading: true , // 是否正在加在中,主要是等图片onload
95- isCanSlide: false , // 是否可以拉动滑动条
96- error: false , // 图片加在失败会出现这个,提示用户手动刷新
97- infoBoxShow: false , // 提示信息是否出现
98- infoText: " " , // 提示等信息
99- infoBoxFail: false , // 是否验证失败
100- timer1: null , // setTimout1
101- closeDown: false , // 为了解决Mac上的click BUG
102- isSuccess: false , // 验证成功
103- resetSvg,
104- imgIndex: - 1 // 用于自定义图片时不会随机到重复的图片
105- };
106- },
107- /** 父级参数 **/
10884 props: {
109- id: { type: String },
11085 canvasWidth: { type: Number , default: 310 }, // 主canvas的宽
11186 canvasHeight: { type: Number , default: 160 }, // 主canvas的高
11287 // 是否出现,由父级控制
@@ -132,6 +107,29 @@ export default {
132107 }
133108 },
134109
110+ data () {
111+ return {
112+ mouseDown: false , // 鼠标是否在按钮上按下
113+ startWidth: 50 , // 鼠标点下去时父级的width
114+ startX: 0 , // 鼠标按下时的X
115+ newX: 0 , // 鼠标当前的偏移X
116+ pinX: 0 , // 拼图的起始X
117+ pinY: 0 , // 拼图的起始Y
118+ loading: false , // 是否正在加在中,主要是等图片onload
119+ isCanSlide: false , // 是否可以拉动滑动条
120+ error: false , // 图片加在失败会出现这个,提示用户手动刷新
121+ infoBoxShow: false , // 提示信息是否出现
122+ infoText: " " , // 提示等信息
123+ infoBoxFail: false , // 是否验证失败
124+ timer1: null , // setTimout1
125+ closeDown: false , // 为了解决Mac上的click BUG
126+ isSuccess: false , // 验证成功
127+ imgIndex: - 1 , // 用于自定义图片时不会随机到重复的图片
128+ isSubmting: false , // 是否正在判定,主要用于判定中不能点击重置按钮
129+ resetSvg,
130+ };
131+ },
132+
135133 /** 生命周期 **/
136134 mounted () {
137135 document .body .appendChild (this .$el );
@@ -144,8 +142,9 @@ export default {
144142 document .addEventListener (" touchend" , this .onRangeMouseUp , false );
145143 if (this .show ) {
146144 document .body .classList .add (" vue-puzzle-overflow" );
145+ this .reset ();
147146 }
148- this . reset ();
147+
149148 },
150149 beforeDestroy () {
151150 clearTimeout (this .timer1 );
@@ -167,6 +166,8 @@ export default {
167166 document .body .classList .add (" vue-puzzle-overflow" );
168167 this .reset ();
169168 } else {
169+ this .isSuccess = false ;
170+ this .infoBoxShow = false ;
170171 document .body .classList .remove (" vue-puzzle-overflow" );
171172 }
172173 }
@@ -247,6 +248,10 @@ export default {
247248 * @param withCanvas 是否强制使用canvas随机作图
248249 */
249250 init (withCanvas ) {
251+ // 防止重复加载导致的渲染错误
252+ if (this .loading && ! withCanvas){
253+ return ;
254+ }
250255 this .loading = true ;
251256 this .isCanSlide = false ;
252257 const c = this .$refs .canvas1 ;
@@ -255,7 +260,10 @@ export default {
255260 const ctx = c .getContext (" 2d" );
256261 const ctx2 = c2 .getContext (" 2d" );
257262 const ctx3 = c3 .getContext (" 2d" );
263+ const isFirefox = navigator .userAgent .indexOf (" Firefox" ) >= 0 && navigator .userAgent .indexOf (" Windows" ) >= 0 ; // 是windows版火狐
258264 const img = document .createElement (" img" );
265+ ctx .fillStyle = " rgba(255,255,255,1)" ;
266+ ctx3 .fillStyle = " rgba(255,255,255,1)" ;
259267 ctx .clearRect (0 , 0 , this .canvasWidth , this .canvasHeight );
260268 ctx2 .clearRect (0 , 0 , this .canvasWidth , this .canvasHeight );
261269
@@ -269,31 +277,26 @@ export default {
269277 // 先画小图
270278 this .paintBrick (ctx);
271279 ctx .closePath ();
272- if (
273- ! (
274- navigator .userAgent .indexOf (" Firefox" ) >= 0 &&
275- navigator .userAgent .indexOf (" Windows" ) >= 0
276- )
277- ) {
278- // 非火狐,在此画外阴影
280+ if (! isFirefox){
281+ ctx .shadowOffsetX = 0 ;
282+ ctx .shadowOffsetY = 0 ;
283+ ctx .shadowColor = " #000" ;
284+ ctx .shadowBlur = 3 ;
285+ ctx .fill ();
286+ ctx .clip ();
287+ } else {
288+ ctx .clip ();
289+ ctx .save ();
279290 ctx .shadowOffsetX = 0 ;
280291 ctx .shadowOffsetY = 0 ;
281292 ctx .shadowColor = " #000" ;
282293 ctx .shadowBlur = 3 ;
283294 ctx .fill ();
295+ ctx .restore ();
284296 }
285297
286- ctx .clip (); // 按照外阴影区域切割
287-
288- ctx .save ();
289- // 小图外阴影
290- ctx .shadowOffsetX = 0 ;
291- ctx .shadowOffsetY = 0 ;
292- ctx .shadowColor = " #000" ;
293- ctx .shadowBlur = 2 ;
294- ctx .fill ();
295- ctx .restore ();
296298 ctx .drawImage (img, x, y, w, h);
299+ ctx3 .fillRect (0 ,0 ,this .canvasWidth ,this .canvasHeight );
297300 ctx3 .drawImage (img, x, y, w, h);
298301
299302 // 设置小图的内阴影
@@ -318,13 +321,8 @@ export default {
318321 ctx .fill ();
319322
320323 // 将小图赋值给ctx2
321- const imgData = ctx .getImageData (
322- this .pinX - 3 , // 为了阴影 是从-3px开始截取,判定的时候要+3px
323- this .pinY - 20 ,
324- this .pinX + this .puzzleBaseSize + 5 ,
325- this .pinY + this .puzzleBaseSize + 5
326- );
327- ctx2 .putImageData (imgData, 0 , this .pinY - 20 );
324+ ctx2 .drawImage (c, this .pinX - 3 ,this .pinY - 20 ,this .pinX + this .puzzleBaseSize + 5 ,this .pinY + this .puzzleBaseSize + 5 ,
325+ 0 , this .pinY - 20 , this .pinX + this .puzzleBaseSize + 5 , this .pinY + this .puzzleBaseSize + 5 );
328326
329327 // 清理
330328 ctx .restore ();
@@ -521,6 +519,7 @@ export default {
521519 },
522520 // 开始判定
523521 submit () {
522+ this .isSubmting = true ;
524523 // 偏差 x = puzzle的起始X - (用户真滑动的距离) + (puzzle的宽度 - 滑块的宽度) * (用户真滑动的距离/canvas总宽度)
525524 // 最后+ 的是补上slider和滑块宽度不一致造成的缝隙
526525 const x = Math .abs (
@@ -542,6 +541,7 @@ export default {
542541 clearTimeout (this .timer1 );
543542 this .timer1 = setTimeout (() => {
544543 // 成功的回调
544+ this .isSubmting = false ;
545545 this .$emit (" success" , x);
546546 }, 800 );
547547 } else {
@@ -555,19 +555,28 @@ export default {
555555 // 800ms后重置
556556 clearTimeout (this .timer1 );
557557 this .timer1 = setTimeout (() => {
558+ this .isSubmting = false ;
558559 this .reset ();
559560 }, 800 );
560561 }
561562 },
562- // 重置
563- reset () {
563+ // 重置 - 重新设置初始状态
564+ resetState () {
564565 this .infoBoxFail = false ;
565566 this .infoBoxShow = false ;
566- this .isCanSlide = true ;
567+ this .isCanSlide = false ;
567568 this .isSuccess = false ;
568569 this .startWidth = this .sliderBaseSize ; // 鼠标点下去时父级的width
569570 this .startX = 0 ; // 鼠标按下时的X
570571 this .newX = 0 ; // 鼠标当前的偏移X
572+ },
573+
574+ // 重置
575+ reset () {
576+ if (this .isSubmting ){
577+ return ;
578+ }
579+ this .resetState ();
571580 this .init ();
572581 }
573582 }
0 commit comments