JAVA后端生成图片滑块验证码 springboot+js完整案例

前言

现在大部分网部都是图片滑块验证码,这个得要与后端联动起来才是确保接口安全性

通过我们系统在发送手机短息时都会选进行滑块验证,但是我们要保证发送短息接口的全安,具体路思如下

那么这个滑块的必须是与后端交互才能保证安全性,而不是前端简单的交互。我们一起来学习一下这个案例怎么实吧

1、验证通过效果如图

2、验证失败效果如图

案例开始

1、我们使用java新建一个springboot工程,并准备几张图片,尺寸是390*180,如下图

添加依赖

xml 复制代码
<dependency>
	<groupId>net.coobird</groupId>
    <artifactId>thumbnailator</artifactId>
    <version>0.4.11</version>
</dependency>

2、新建三个响应的类

2.1 WebReturn类如下

java 复制代码
@Data
public class WebReturn {

    RetCode code;
    Object data;

    public WebReturn(RetCode code, Object data) {
        this.code = code;
        this.data = data;
    }
}

2.2 RetCode类如下

java 复制代码
public enum  RetCode {
    IMAGE_REQ_SUCCESS(1,"图片请求成功"),
    IMAGE_REQ_FAIL(2,"图片请求失败"),
    VERIFI_REQ_SUCCESS(3,"图片验证成功"),
    VERIFI_REQ_FAIL(4,"图片验证失败");

    int code;
    String message;

    RetCode(int code, String message) {
        this.code = code;
        this.message = message;
    }



    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

2.3 ImageResult类如下

java 复制代码
@Data
public class ImageResult {

    int xpos;//滑块的坐标x轴
    int ypos;//滑块的坐标y轴
    int cutImageWidth;//滑块的宽
    int cutImageHeight;//滑块的高

    String  cutImage;//滑块图片
    String  oriImage;//背景图(初扣掉滑块的图)

}

3、新建一个图片滑块生成的工具类

java 复制代码
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
@Slf4j
public class ImgUtil {

    //图片的路径
    private  String classpath = "classpath*:img/slider/*.*";
    //图片的最大大小  (可以根据实际需要进行高调整,对应的图片尺寸也得是一致)
    private  static int IMAGE_MAX_WIDTH = 380;
    private  static int IMAGE_MAX_HEIGHT = 190;
    //抠图上面的半径
    private   static int RADIUS = IMAGE_MAX_WIDTH/38;
    //抠图区域的高度
    private   static int CUT_HEIGHT = IMAGE_MAX_WIDTH/7;
    //抠图区域的宽度
    private   static int CUT_WIDTH = IMAGE_MAX_WIDTH/7;
    //被扣地方填充的颜色
    private   static int FLAG = 0xffffff;
    //抠图部分凸起的方向
    private  Location location;
    ImageResult imageResult = new ImageResult();
    private  String ORI_IMAGE_KEY = "ORI_IMAGE_KEY";
    private  String CUT_IMAGE_KEY = "CUT_IMAGE_KEY";

    private  int XPOS;
    private  int YPOS;

    @Data
    private  class ImageMessage{
        private int xpos;
        private int ypos;
        private int cutImageWidth;
        private int cutImageHeight;
    }

    ImageMessage imageMessage = new ImageMessage();


    /**
     *功能描述 获取抠图区的坐标原点
     */
    public  void createXYPos(BufferedImage oriImage){

        int height = oriImage.getHeight();
        int width = oriImage.getWidth();


        XPOS = new Random().nextInt(width-CUT_WIDTH-RADIUS);
        YPOS = new Random().nextInt(height-CUT_HEIGHT-RADIUS-RADIUS)+RADIUS;

        //确保横坐标位于2/4--3/4
        int div = (IMAGE_MAX_WIDTH/4);

        if(XPOS/div ==  0 ){
            XPOS = XPOS + div*2;
        }
        else if(XPOS/div ==  1 ){
            XPOS = XPOS + div;
        }
        else if(XPOS/div ==  3 ){
            XPOS = XPOS - div;
        }

    }
    /**
     *功能描述 对外提供的接口
     */
    public  ImageResult imageResult() throws IOException{
        return imageResult(getRandomImage());
    }

    public  ImageResult imageResult(BufferedImage oriBufferedImage) throws IOException {

        //检测图片大小
        oriBufferedImage = checkImage(oriBufferedImage);

        //初始化原点坐标
        createXYPos(oriBufferedImage);
        //获取被扣图像的标志图
        int[][] blockData = getBlockData(oriBufferedImage);
        //printBlockData(blockData);
        //计算抠图区域的信息
        createImageMessage();

        //获取扣了图的原图和被扣部分的图
        Map<String,BufferedImage> imageMap =  cutByTemplate(oriBufferedImage,blockData);

        imageResult.setOriImage(ImageBase64(imageMap.get(ORI_IMAGE_KEY)));
        imageResult.setCutImage(ImageBase64(imageMap.get(CUT_IMAGE_KEY)));

        imageResult.setXpos(imageMessage.getXpos());
        imageResult.setYpos(imageMessage.getYpos());
        imageResult.setCutImageWidth(imageMessage.getCutImageWidth());
        imageResult.setCutImageHeight(imageMessage.getCutImageHeight());

        return imageResult;
    }


    /**
     *功能描述
     * @Description 计算抠图的相关参数
     */
    private  void createImageMessage(){
        int x = 0,y = 0;
        int w = 0, h = 0;

        if(location == Location.UP){
            x = XPOS;
            y = YPOS - RADIUS;
            w = CUT_WIDTH;
            h = CUT_HEIGHT + RADIUS;
        }else if(location == Location.LEFT){
            x = XPOS-RADIUS;
            y = YPOS;
            w = CUT_WIDTH + RADIUS;
            h = CUT_HEIGHT;
        }else if(location == Location.DOWN){
            x = XPOS;
            y = YPOS;
            w = CUT_WIDTH;
            h = CUT_HEIGHT + RADIUS;
        }else if(location == Location.RIGHT){
            x = XPOS;
            y = YPOS;
            w = CUT_WIDTH + RADIUS;
            h = CUT_HEIGHT;
        }

        imageMessage.setXpos(x);
        imageMessage.setYpos(y);
        imageMessage.setCutImageHeight(h);
        imageMessage.setCutImageWidth(w);
    }
    /**
     *功能描述
     * @Description  检测图片大小是否符合要求
     */
    private  BufferedImage checkImage(BufferedImage image) throws IOException {
        if((image.getWidth()  == IMAGE_MAX_WIDTH) || (image.getHeight()  == IMAGE_MAX_HEIGHT)){
            return image;
        }else if((image.getWidth()  < IMAGE_MAX_WIDTH) || (image.getHeight()  < IMAGE_MAX_HEIGHT)){
            log.info("图片太小.不符合要求w*h[380*190]");
            throw  new IllegalArgumentException("图片太小.不符合要求w*h[380*190]");
        } else {
            log.info("压缩图片");
            return compressImage(image,IMAGE_MAX_WIDTH,IMAGE_MAX_HEIGHT);
        }
    }


    private Color color(int rgb){
        int b = (0xff & rgb);
        int g = (0xff & (rgb >> 8));
        int r = (0xff & (rgb >> 16));
        return new Color(r, g, b);
    }


    /**
     *功能描述 获取抠完图的原图和被扣出来的图
     */
    public  Map<String,BufferedImage> cutByTemplate(BufferedImage oriImage,  int[][] blockData){
        Map<String,BufferedImage> imgMap = new HashMap<>();
        BufferedImage cutImage = new BufferedImage(imageMessage.cutImageWidth,imageMessage.cutImageHeight,oriImage.getType());
        // 获取Graphics2D
        Graphics2D g2d = cutImage.createGraphics();

        //透明化整张图
        cutImage = g2d.getDeviceConfiguration()
                .createCompatibleImage(imageMessage.cutImageWidth,imageMessage.cutImageHeight, Transparency.BITMASK);
        g2d.dispose();
        g2d = cutImage.createGraphics();
        // 背景透明代码结束
        int xmax = imageMessage.xpos + imageMessage.cutImageWidth;
        int ymax = imageMessage.ypos + imageMessage.cutImageHeight;

        for(int x = imageMessage.xpos; x< xmax && x>=0; x++){
            for(int y = imageMessage.ypos; y < ymax && y>=0; y++){
                int oriRgb = oriImage.getRGB(x,y);
                if(blockData[x][y] == FLAG){
                    oriImage.setRGB(x,y,FLAG);
                    //描边   判断是否为边界,如果是边界则填充为白色
                    if(blockData[x-1][y] != FLAG || blockData[x+1][y] != FLAG || blockData[x][y+1] != FLAG || blockData[x][y-1] != FLAG){
                        g2d.setColor(color(0xffffff));
                    }else{
                        g2d.setColor(color(oriRgb));
                    }
                    g2d.setStroke(new BasicStroke(1f));
                    g2d.fillRect(x-imageMessage.xpos, y-imageMessage.ypos, 1, 1);
                }
            }
        }

        // 释放对象
        g2d.dispose();
        imgMap.put(ORI_IMAGE_KEY,oriImage);
        imgMap.put(CUT_IMAGE_KEY,cutImage);
        return imgMap;
    }
    /**
     *功能描述
     * @Description 获取抠图数据,被扣的像素点将使用FLAG进行标记
     * @return:  int[][]
     */
    public  int[][] getBlockData(BufferedImage oriImage){

        int height = oriImage.getHeight();
        int width = oriImage.getWidth();
        int[][] blockData =new int[width][height];

        Location locations[] = {Location.UP,Location.LEFT,Location.DOWN,Location.RIGHT};

        //矩形
        //此处还可以优化,进行区域扫描
        for(int x = 0; x< width && x>=0; x++){
            for(int y = 0; y < height && y>=0; y++){
                blockData[x][y] = 0;
                if ( (x > XPOS) && (x < (XPOS+CUT_WIDTH))
                        && (y > YPOS) && (y < (YPOS+CUT_HEIGHT))){
                    blockData[x][y] = FLAG;
                }
            }
        }

        //圆形突出区域
        //突出圆形的原点坐标(x,y)
        int xBulgeCenter=0,yBulgeCenter=0;
        int xConcaveCenter=0,yConcaveCenter=0;

        //位于矩形的哪一边,0123--上下左右
        location = locations[new Random().nextInt(4)];
        if(location == Location.UP){
            //上 凸起
            xBulgeCenter = XPOS +  CUT_WIDTH/2;
            yBulgeCenter = YPOS;
            //左 凹陷
            xConcaveCenter = XPOS ;
            yConcaveCenter = YPOS + CUT_HEIGHT/2;
        }else if(location == Location.DOWN){
            //下 凸起
            xBulgeCenter = XPOS +  CUT_WIDTH/2;
            yBulgeCenter = YPOS + CUT_HEIGHT;
            //右 凹陷
            xConcaveCenter = XPOS +  CUT_WIDTH;
            yConcaveCenter = YPOS + CUT_HEIGHT/2;
        }else if(location == Location.LEFT){
            //左 凸起
            xBulgeCenter = XPOS ;
            yBulgeCenter = YPOS + CUT_HEIGHT/2;
            //下 凹陷
            xConcaveCenter = XPOS +  CUT_WIDTH/2;
            yConcaveCenter = YPOS + CUT_HEIGHT;
        }else {
            //Location.RIGHT
            //右 凸起
            xBulgeCenter = XPOS +  CUT_WIDTH;
            yBulgeCenter = YPOS + CUT_HEIGHT/2;
            //上 凹陷
            xConcaveCenter = XPOS +  CUT_WIDTH/2;
            yConcaveCenter = YPOS;

        }

        //半径的平方
        int RADIUS_POW2 = RADIUS * RADIUS;

        //凸起部分
        for(int x = xBulgeCenter-RADIUS; x< xBulgeCenter+RADIUS && x>=0; x++){
            for(int y = yBulgeCenter-RADIUS; y < yBulgeCenter+RADIUS && y>=0; y++){
                if(Math.pow((x-xBulgeCenter),2) + Math.pow((y-yBulgeCenter),2) < RADIUS_POW2){
                    blockData[x][y] = FLAG;
                }
            }
        }

        //凹陷部分
        for(int x = xConcaveCenter-RADIUS; x< xConcaveCenter+RADIUS && x>=0; x++){
            for(int y = yConcaveCenter-RADIUS; y < yConcaveCenter+RADIUS && y>=0; y++){
                if(Math.pow((x-xConcaveCenter),2) + Math.pow((y-yConcaveCenter),2) <= RADIUS_POW2){
                    blockData[x][y] = 0;
                }
            }
        }
        return blockData;
    }




    /**
     *功能描述 将图片转为base64存储
     */
    private  String ImageBase64(BufferedImage bufferedImage) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ImageIO.write(bufferedImage, "png", out);
        //转成byte数组
        byte[] bytes = out.toByteArray();
        Base64.Encoder encoder = Base64.getEncoder();
        //生成BASE64编码
        return encoder.encodeToString(bytes);
    }

    /**
     * 随机获取一个图片文件
     * @return
     * @throws Exception
     */
    private  BufferedImage getRandomImage() throws IOException {
        try {
            //使用resource获取resource文件【注意:即使打成jar包也有效】
            ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
            Resource[] resources = resourcePatternResolver.getResources(classpath);

            if (resources.length <= 0) {
                throw new IOException("该文件夹内没有文件!");
            } else {
                int index = new Random().nextInt(resources.length);
                InputStream inputStream = resources[index].getInputStream();
                BufferedImage marioBufferedImage = ImageIO.read(inputStream);
                return marioBufferedImage;
            }
        } catch (IOException e) {
            log.info("读取文件失败:{}", e);
            throw new IOException("读取文件失败!");
        }
    }

    /**
     *功能描述  压缩图片
     * @author lgj
     * @Description
     * @date 3/30/20
     * @param:
     * @return:  java.awt.image.BufferedImage
     *
     */
    private  BufferedImage compressImage(BufferedImage image,int width,int height) throws IOException{
        return  Thumbnails.of(image)
                .forceSize(width,height)
                //.width(width).height(height)
                .asBufferedImage();
    }
    /**
     *功能描述
     * @Description  抠图部分凸起的区域
     */
    private enum Location {
        UP,
        LEFT,
        DOWN,
        RIGHT;
    }
}

4、新建一个controller

java 复制代码
@Slf4j
@RestController
@RequestMapping("/slider")
public class SliderController {

    private  int xPosCache = 0;//生产环境请把这个值存入redis中

    @RequestMapping("/image")
    public WebReturn image(){
        ImageResult imageResult = null;
        try{
            imageResult = new ImgUtil().imageResult();//生成图片
            xPosCache = imageResult.getXpos();//生产环境请把这个值存入redis中
            imageResult.setXpos(0);//清空x值
            return new WebReturn(RetCode.IMAGE_REQ_SUCCESS,imageResult);
        }catch(Exception ex){
            log.error(ex.getMessage());
            ex.printStackTrace();
            return new WebReturn(RetCode.IMAGE_REQ_FAIL,null);
        }
    }

    @RequestMapping("/verification")
    public WebReturn verification(@RequestParam("moveX") int moveX){
        log.info("/slider/verification/{}",moveX);
        int MOVE_CHECK_ERROR = 2;//允许的误差范围,这里设置为2个像素
        //xPosCache   生产请从redis中读取,使用完并立即请除
        if(( moveX < ( xPosCache + MOVE_CHECK_ERROR)) && ( moveX >  (xPosCache - MOVE_CHECK_ERROR))){
            log.info("验证正确");
            //生产这个可以返回临时授权码
            return new WebReturn(RetCode.VERIFI_REQ_SUCCESS,true);
        }
        return new WebReturn(RetCode.VERIFI_REQ_FAIL,false);
    }
}

5、最后新建一个页面

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>

    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>

    <style >
        html body {
            height: 100%;
            width: 100%;
        }

        #captchaContainer{
            position: absolute;
            top: 50px;
            left: 40%;
          /*  background-color: #f57a7a;*/
            height: 275px;
            width: 260px;
        }
        .header{

            position: absolute;
            top: 0px;
            left: 0px;
            background-color: rgb(245, 236, 236);
            height: 40px;
            width: 380px;
        }
        .headerText{
            position: absolute;
            top: 13px;
            left: 140px;
            height: 40px;

            color:#66c523;
            font:18px/14px Georgia, "Times New Roman", Times, serif;


        }

        #captchaImg{
            position: absolute;
            left: 0;
            top: 40px;
            height: 190px;
            width: 380px;
            -webkit-user-select: none;
            -moz-user-select: none;
            -ms-user-select: none;
            user-select: none;
            border: none


        }
        #oriImg{
            position: absolute;
            left: 0px;
            top: 0px;
            width: 380px;
            height: 190px;

            -webkit-user-select: none;
            -moz-user-select: none;
            -ms-user-select: none;
            user-select: none;
            border: none

        }
        #cutImg{
            position: absolute;
            border: none;
            left: 0px;
        }
        .sliderContainer {
            position: absolute;
            bottom: 0;
            left: 0px;
            text-align: center;
            width: 380px;
            height: 40px;
            line-height: 40px;
            background: #f7f9fa;
            color: #45494c;
            border: 1px solid #e4e7eb;

        }

        .sliderContainer_success{
            border: 1px solid hsl(125, 93%, 44%);
        }
        .sliderContainer_fail{
            border: 1px solid #ec3655;
        }

        .slider {
            position: absolute;
            top: 0;
            left: 0px;
            width: 40px;
            height: 40px;
            background: #fff;
            box-shadow: 0 0 3px rgba(0, 0, 0, 0.3);
            transition: background .2s linear;
            cursor: pointer;
            cursor: grab;
        }
        .slider_success{
            border: 1px solid hsl(125, 93%, 44%);
        }
        .slider_fail{
            border: 1px solid #ec3655;
        }



        .sliderContainer_active .slider {
            height: 38px;
            top: -1px;
            border: 1px solid #1991FA;
        }

        .sliderContainer_active .sliderMask {
            height: 38px;
            border-width: 1px;
        }

        .sliderContainer_success .slider {
            height: 38px;
            top: -1px;
            margin-left: -1px;
            border: 1px solid #52CCBA;
            background-color: #52CCBA !important;
        }

        .sliderContainer_success .sliderMask {
            height: 38px;
            border: 1px solid #52CCBA;
            background-color: #D2F4EF;
        }

        .sliderContainer_success .sliderIcon {
            background-position: 0 0 !important;
        }

        .sliderContainer_fail .slider {
            height: 38px;
            top: -1px;
            border: 1px solid #f57a7a;
            background-color: #f57a7a !important;
        }

        .sliderContainer_fail .sliderMask {
            height: 38px;
            border: 1px solid #f57a7a;
            background-color: #fce1e1;
        }

        .sliderContainer_fail .sliderIcon {
            top: 14px;
            background-position: 0 -82px !important;
        }
        .sliderContainer_active .sliderText, .sliderContainer_success .sliderText, .sliderContainer_fail .sliderText {
            display: none;
        }

        .sliderMask {
            position: absolute;
            left: 0;
            top: 0;
            height: 40px;
            border: 0 solid #1991FA;
            background: #D1E9FE;
        }



        .slider:active {
            cursor: grabbing;
        }

        .slider:hover {
            background: #1991FA;
        }

        .slider:hover .sliderIcon {
            background-position: 0 -13px;
        }

        .sliderIcon {
            position: absolute;
            top: 15px;
            left: 13px;
            width: 14px;
            height: 12px;
            background: url(http://cstaticdun.126.net//2.6.3/images/icon_light.f13cff3.png) 0 -26px;
            background-size: 34px 471px;
        }

        .refreshIcon {
            position: absolute;
            right: 0;
            top: 0;
            width: 34px;
            height: 34px;
            cursor: pointer;
            background: url(http://cstaticdun.126.net//2.6.3/images/icon_light.f13cff3.png) 0 -437px;
            background-size: 34px 471px;
        }



    </style>

</head>
<body>
    
    <div id="captchaContainer">
        <!-- 标题栏 -->
        <div class="header">
            <span class="headerText">图片滑动验证</span>
            <span class="refreshIcon"/>
        </div> 

        <!-- 图片显示区域 -->
        <div id="captchaImg">
            <img id="oriImg" src="dd" alt="原图"/>
            <img id="cutImg" src="sa" alt="抠图"/>
        </div>
        <!--滑块显示区域-->
         <div class="sliderContainer">
            <div class="sliderMask">
                <div class="slider">
                    <span class="sliderIcon"></span>
                </div>
            </div>
            <span class="sliderText">向右滑动填充拼图</span>
            
        </div> 

        
    </div>


    
</body>

<script>

    //图片显示使用base64时的前缀,src=base64PrefixPath + imgBase64Value
    var base64PrefixPath="data:image/png;base64,";

    var IMAGE_WIDTH = 380;
    //初始化
    //滑块初始偏移量
    var sliderInitOffset = 0;
    //滑块移动的最值
    var MIN_MOVE = 0;
    var MAX_MOVE = 0;
    //鼠标按下标志
    var mousedownFlag=false;
    //滑块移动的距离
    var moveX;
    //滑块位置检测允许的误差,正负2
    var MOVE_CHECK_ERROR = 2;
    //滑块滑动使能
    var moveEnable = true;

    var ImageMsg = {
            //抠图的坐标
            xpos: 0,
            ypos: 0,
            //抠图的大小
            cutImageWidth: 0,
            cutImageHeight: 0,
            //原图的base64
            oriImageSrc: 0,
            //抠图的base64
            cutImageSrc: 0,
    }



   //加载页面时进行初始化
    function init(){
        console.log("init")

        moveEnable = true;
        mousedownFlag=false;

        $(".slider").css("left",0+"px");

        initClass();

        MAX_MOVE = IMAGE_WIDTH - ImageMsg.cutImageWidth;

        console.log("ImageMsg = " + ImageMsg)
        $("#cutImg").css("left",0+"px");
        $("#oriImg").attr("src",ImageMsg.oriImageSrc)
        $("#cutImg").attr("src",ImageMsg.cutImageSrc)
        $("#cutImg").css("width",ImageMsg.cutImageWidth)
        $("#cutImg").css("height",ImageMsg.cutImageHeight)
        $("#cutImg").css("top",ImageMsg.ypos)




    }
    //加载页面时
    $(function(){

        httpRequest.requestImage.request();
    })

    var httpRequest={
      //请求获取图片
      requestImage:{
        path: "slider/image",
        request:function(){
            $.get(httpRequest.requestImage.path,function(data,status){

                console.log(data)
                console.log(data.message);

                if(data.data != null){

                    ImageMsg.oriImageSrc = base64PrefixPath + data.data.oriImage;
                    ImageMsg.cutImageSrc = base64PrefixPath + data.data.cutImage;
                    ImageMsg.xpos = data.data.xpos;
                    ImageMsg.ypos = data.data.ypos;
                    ImageMsg.cutImageWidth = data.data.cutImageWidth;
                    ImageMsg.cutImageHeight = data.data.cutImageHeight;

                    init();
                }

          });
        },
      },
      //请求验证
      requestVerification:{
        path: "slider/verification",
        request:function(){
            $.get(httpRequest.requestVerification.path,{moveX:(moveX)},function(data,status){
                console.log(data)
                console.log(data.code);
                console.log(data.message);

                if(data.data == true){
                    checkSuccessHandle();
                }
                else{
                    checkFailHandle();
                }
          });
        },
      },
    }

    //刷新图片操作
    $(".refreshIcon").on("click",function(){
        httpRequest.requestImage.request();
    })

    //滑块鼠标按下
    $(".slider").mousedown(function(event){
        console.log("鼠标按下mousedown:"+event.clientX + " " + event.clientY);
        sliderInitOffset = event.clientX;  
        mousedownFlag = true;

        

        //滑块绑定鼠标滑动事件
        $(".slider").on("mousemove",function(event){
            if(mousedownFlag  == false){
              return;
            }
            if(moveEnable == false){
              return
            }

            moveX = event.clientX - sliderInitOffset;

            moveX<MIN_MOVE?moveX=MIN_MOVE:moveX=moveX;
            moveX>MAX_MOVE?moveX=MAX_MOVE:moveX=moveX;


            $(this).css("left",moveX+"px");
            $("#cutImg").css("left",moveX+"px");
        })
    })
    //滑块鼠标弹起操作
    $(".slider").mouseup(function(event){
        console.log("mouseup:"+event.clientX + " " + event.clientY);
        sliderInitOffset = 0;
        $(this).off("mousemove");
        mousedownFlag=false;
        console.log("moveX = " + moveX)
        checkLocation();
        
    })
    //检测滑块 位置是否正确
    function checkLocation(){

        moveEnable = false;

        //后端请求检测滑块位置
        httpRequest.requestVerification.request();
    }

    function checkSuccessHandle(){
      $(".sliderContainer").addClass("sliderContainer_success");
      $(".slider").addClass("slider_success");
    }
    function checkFailHandle(){
      $(".sliderContainer").addClass("sliderContainer_fail");
      $(".slider").addClass("slider_success");
    }

    function initClass(){
      $(".sliderContainer").removeClass("sliderContainer_success");
      $(".slider").removeClass("slider_success");
  
      $(".sliderContainer").removeClass("sliderContainer_fail");
      $(".slider").removeClass("slider_fail");
    }
    


</script>


</html>

最后

到这里我们的案例代码已经写好了,运程工程访问就可以了。

http://localhost:9005/home.html

本文章提供大家学习,欢迎你大家留言提供您的保贵意见
=如果本文对您有帮助,麻烦您给博主点个赞吧!=

相关推荐
lkbhua莱克瓦241 小时前
Java基础——集合进阶3
java·开发语言·笔记
ruleslol1 小时前
SpringBoot面试题03-BeanFactory
spring boot
顺凡1 小时前
删一个却少俩:Antd Tag 多节点同时消失的原因
前端·javascript·面试
蓝-萧2 小时前
使用Docker构建Node.js应用的详细指南
java·后端
多喝开水少熬夜2 小时前
Trie树相关算法题java实现
java·开发语言·算法
前端大卫2 小时前
动态监听DOM元素高度变化
前端·javascript
Cxiaomu2 小时前
React Native App 图表绘制完整实现指南
javascript·react native·react.js
lkbhua莱克瓦242 小时前
Java基础——集合进阶用到的数据结构知识点1
java·数据结构·笔记·github
qq. 28040339842 小时前
vue介绍
前端·javascript·vue.js
Mr.Jessy3 小时前
Web APIs 学习第五天:日期对象与DOM节点
开发语言·前端·javascript·学习·html