Finally realized Sliding Puzzle verification code, vue

Reason: Before you see when beep beep miles miles logged on the official website there is a puzzle code, it is curious how to achieve. Then think of himself in one. I would let you see the end result. And then a little later dismantling code.

8f7fce7292dd42968558dbc8df5ac7c1


Why think of writing this feature yet, mainly because the puzzle verification code will be more complex and in-depth in the front here. Compared spelling of text, pictures 12306 code no puzzle code requirements for front-end to the complex, and difficult.

I summarize knowledge:

1, pop function

2, pop-based positioning elements

3, drag elements

4, canvas graphics

5, the underlying logic

A, and pop pop assembly

Sorry, here I am lazy directly with the elementUI of el-popover component, so do not understand direct instructions elementUI see the official website of the junior partner.

I also research and write a piece of functional components (based popper.js)

Second, the preparation of infrastructure

Html content belong to this foundation, also the title of the party

Three, canvas draw pictures

1, canvas rendering external img pictures

Code:

let mainDom = document.querySelector("#codeImg");let bg = mainDom.getContext("2d");let width = mainDom.width;let height = mainDom.height;let blockDom = document.querySelector("#sliderBlock");let block = blockDom.getContext("2d");
//重新赋值,让canvas进行重新绘制
blockDom.height = height;
mainDom.height = height;let imgsrc = require("../assets/images/back.jpg");let img = document.createElement("img");
img.style.objectFit = "scale-down";
img.src = imgsrc;
img.onload = function() {
 bg.drawImage(img, 0, 0, width, height); block.drawImage(img, 0, 0, width, height);
};复制代码

Here I draw two canvas, because a background is a slide

Core is

let mainDom = document.querySelector("#codeImg");let imgsrc = require("../assets/images/back.jpg");let bg = mainDom.getContext("2d");let img = document.createElement("img");
img.onload = function() {
 bg.drawImage(img, 0, 0, width, height);
};
复制代码

2, canvas draw slider part

Is this chart, this has some knowledge, is not difficult, but very complicated.

a7864a1c56964775927078247a3e92bb


Code section:

drawBlock(ctx, xy = { x: 254, y: 109, r: 9 }, type) {
 let x = xy.x,
 y = xy.y,
 r = xy.r,
 w = 40;
 let PI = Math.PI; //绘制
 ctx.beginPath(); //left
 ctx.moveTo(x, y); //top
 ctx.arc(x + (w + 5) / 2, y, r, -PI, 0, true);
 ctx.lineTo(x + w + 5, y); //right
 ctx.arc(x + w + 5, y + w / 2, r, 1.5 * PI, 0.5 * PI, false);
 ctx.lineTo(x + w + 5, y + w); //bottom
 ctx.arc(x + (w + 5) / 2, y + w, r, 0, PI, false);
 ctx.lineTo(x, y + w);
 ctx.arc(x, y + w / 2, r, 0.5 * PI, 1.5 * PI, true);
 ctx.lineTo(x, y); //修饰,没有会看不出效果
 ctx.lineWidth = 1;
 ctx.fillStyle = "rgba(255, 255, 255, 0.5)";
 ctx.strokeStyle = "rgba(255, 255, 255, 0.5)";
 ctx.stroke();
 CTX [type] (); 
 ctx.globalCompositeOperation = "XOR"; 
} copy the code

please explain:

Parameters are passed canvas objects

x, y-axis data

Shear is filled canvas function (fill, clip)

Draw difficulty :( very important, otherwise you can not understand how it draws)

The main draw is the draw here need to understand is that you set a starting point according to the coordinates, and then you draw a second line when you connect to the second point, and finally back to square one in turn connected to form a complete graphics.

b96e9b6c43f34ecfa9868d1eebba350b


Use the arc parameters, mainly to see the map

fill for partially filled drawing, clip is cut out part of the drawing, you can take advantage of the emergence of a picture and deducted a cropped out of the picture.

After the completion of the function that is my. It can directly take to use.

3, so that the sliding element after following the mouse clicks

In fact, here the principle is very simple, is to have a point of attention.

principle:

After clicking the mouse coordinates of the current record, and then with (mousemove) when scrolling left and top value to modify elements on the line.

Another point is that the mouse flick will lead to the loss of sliding effect, where needed document, is not the element level monitoring.

I just need to identify the elements above press mousedown

Code:

//鼠标按下drag(e) { console.log("鼠标按下", e); let dom = e.target; //dom元素
 let slider = document.querySelector("#sliderBlock"); //滑块dom
 const downCoordinate = { x: e.x, y: e.y }; //正确的滑块数据
 let checkx = Number(this.slider.mx) - Number(this.slider.bx); //x轴数据
 let x = 0; const move = moveEV => {
 x = moveEV.x - downCoordinate.x; //y = moveEV.y - downCoordinate.y;
 if (x >= 251 || x <= 0) return false;
 dom.style.left = x + "px"; //dom.style.top = y + "px";
 slider.style.left = x + "px";
 }; const up = () => { document.removeEventListener("mousemove", move); document.removeEventListener("mouseup", up);
 dom.style.left = ""; console.log(x, checkx); let max = checkx - 5; let min = checkx - 10; //允许正负误差1
 if ((max >= x && x >= min) || x === checkx) { console.log("滑动解锁成功"); this.puzzle = true; this.tips = "验证成功";
 setTimeout(() => { this.visible = false;
 }, 500);
 } else { console.log("拼图位置不正确"); this.tips = "验证失败,请重试"; this.puzzle = false; this.canvasInit();
 }
 }; document.addEventListener("mousemove", move); document.addEventListener("mouseup", up);
}复制代码

4、总结

核心点比较多,写过之后发现不难,关键在于去写

个人该页面git地址:https://github.com/ht-sauce/dream

该页面处于项目的

86aee8687c3b432bb2781457657387eb


路由访问为:http://localhost:8080/consumer

5、完整的页面代码

<template>
 <div id="login">
 <el-form class="loginFrom" :model="logindata" :rules="rules" ref="ruleForm">
 <el-form-item class="login-item">
 <h1 class="login-title">海天酱油登录中心</h1>
 </el-form-item>
 <el-form-item prop="userName">
 <el-input
 class="login-inputorbuttom"
 prefix-icon="el-icon-user"
 placeholder="登录名"
 v-model="logindata.userName"
 ></el-input>
 </el-form-item>
 <el-form-item prop="password">
 <el-input
 class="login-inputorbuttom"
 prefix-icon="el-icon-lock"
 placeholder="密码"
 v-model="logindata.password"
 ></el-input>
 </el-form-item>
 <!--<el-form-item prop="verificationCode">
 <el-input
 class="login-inputorbuttom"
 v-model="logindata.verificationCode"
 ></el-input>
 </el-form-item>-->
 <el-form-item class="login-item">
 <el-button
 class="login-inputorbuttom login-bottom"
 type="primary"
 v-popover:popover
 @click="visible = !visible"
 >登 录</el-button
 >
 </el-form-item>
 </el-form>
 <!--验证码弹窗-->
 <el-popover
 popper-class="slidingPictures"
 ref="popover"
 trigger="manual"
 v-model="visible"
 >
 <div class="sliding-pictures">
 <div class="vimg">
 <canvas id="sliderBlock"></canvas>
 <canvas id="codeImg"></canvas>
 </div>
 <div class="slider">
 <div class="track" :class="{ pintuTrue: puzzle }">
 {{ tips }}
 </div>
 <div class="button el-icon-s-grid" @mousedown.prevent="drag"></div>
 </div>
 <div class="operation">
 <span
 title="关闭验证码"
 @click="visible = false"
 class="el-icon-circle-close"
 ></span>
 <span
 title="刷新验证码"
 @click="canvasInit"
 class="el-icon-refresh-left"
 ></span>
 </div>
 </div>
 </el-popover>
 </div></template><script>export default { name: "login",
 data() { return { tips: "拖动左边滑块完成上方拼图", logindata: { userName: "", password: "", verificationCode: ""
 }, rules: {}, visible: false, //滑块x轴数据
 slider: { mx: 0, bx: 0
 }, //拼图是否正确
 puzzle: false
 };
 }, watch: {
 visible(e) { if (e === true) { this.canvasInit(); this.puzzle = false;
 }
 }
 },
 beforeCreate() {},
 created() {},
 beforeMount() {},
 mounted() {}, methods: { //拼图验证码初始化
 canvasInit() { //生成指定区间的随机数
 const random = (min, max) => { return Math.floor(Math.random() * (max - min + 1) + min);
 }; //x: 254, y: 109
 let mx = random(127, 244),
 bx = random(10, 128),
 y = random(10, 99); this.slider = { mx, bx }; this.draw(mx, bx, y);
 }, //鼠标按下
 drag(e) { console.log("鼠标按下", e); let dom = e.target; //dom元素
 let slider = document.querySelector("#sliderBlock"); //滑块dom
 const downCoordinate = { x: e.x, y: e.y }; //正确的滑块数据
 let checkx = Number(this.slider.mx) - Number(this.slider.bx); //x轴数据
 let x = 0; const move = moveEV => {
 x = moveEV.x - downCoordinate.x; //y = moveEV.y - downCoordinate.y;
 if (x >= 251 || x <= 0) return false;
 dom.style.left = x + "px"; //dom.style.top = y + "px";
 slider.style.left = x + "px";
 }; const up = () => { document.removeEventListener("mousemove", move); document.removeEventListener("mouseup", up);
 dom.style.left = ""; console.log(x, checkx); let max = checkx - 5; let min = checkx - 10; //允许正负误差1
 if ((max >= x && x >= min) || x === checkx) { console.log("滑动解锁成功"); this.puzzle = true; this.tips = "验证成功";
 setTimeout(() => { this.visible = false;
 }, 500);
 } else { console.log("拼图位置不正确"); this.tips = "验证失败,请重试"; this.puzzle = false; this.canvasInit();
 }
 }; document.addEventListener("mousemove", move); document.addEventListener("mouseup", up);
 },
 draw(mx = 200, bx = 20, y = 50) { let mainDom = document.querySelector("#codeImg"); let bg = mainDom.getContext("2d"); let width = mainDom.width; let height = mainDom.height; let blockDom = document.querySelector("#sliderBlock"); let block = blockDom.getContext("2d"); //重新赋值,让canvas进行重新绘制
 blockDom.height = height;
 mainDom.height = height; let imgsrc = require("../assets/images/back.jpg"); let img = document.createElement("img");
 img.style.objectFit = "scale-down";
 img.src = imgsrc;
 img.onload = function() {
 bg.drawImage(img, 0, 0, width, height);
 block.drawImage(img, 0, 0, width, height);
 }; let mainxy = { x: mx, y: y, r: 9 }; let blockxy = { x: bx, y: y, r: 9 }; this.drawBlock(bg, mainxy, "fill"); this.drawBlock(block, blockxy, "clip");
 }, //绘制拼图
 drawBlock(ctx, xy = { x: 254, y: 109, r: 9 }, type) { let x = xy.x,
 y = xy.y,
 r = xy.r,
 w = 40; let PI = Math.PI; //绘制
 ctx.beginPath(); //left
 ctx.moveTo(x, y); //top
 ctx.arc(x + (w + 5) / 2, y, r, -PI, 0, true);
 ctx.lineTo(x + w + 5, y); //right
 ctx.arc(x + w + 5, y + w / 2, r, 1.5 * PI, 0.5 * PI, false);
 ctx.lineTo(x + w + 5, y + w); //bottom
 ctx.arc(x + (w + 5) / 2, y + w, r, 0, PI, false);
 ctx.lineTo(x, y + w);
 ctx.arc(x, y + w / 2, r, 0.5 * PI, 1.5 * PI, true);
 ctx.lineTo(x, y); //修饰,没有会看不出效果
 ctx.lineWidth = 1;
 ctx.fillStyle = "rgba(255, 255, 255, 0.5)";
 ctx.strokeStyle = "rgba(255, 255, 255, 0.5)";
 ctx.stroke();
 ctx[type]();
 ctx.globalCompositeOperation = "xor";
 }
 }
};</script><style>.slidingPictures { padding: 0; width: 300px; border-radius: 2px;
}</style><style scoped lang="scss"></style>

At last

Like you can point a concern, a small Coke is not easy to do

519fce4d340c4ebca62d0a29b0e0346a



Guess you like

Origin blog.51cto.com/14516511/2438650