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.
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.
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.
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
该页面处于项目的
路由访问为: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