首页 > 试题广场 >

拖拽拼图

[编程题]拖拽拼图
  • 热度指数:361 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
页面左边为可以使用的拼图,右边为拼图的位置,两者通过序列号对应,页面元素均已经标记id。
请完成drag函数,当执行drag后,可以实现如下需求
1. 用户可以把左边的拼图块全部移到右边对应位置,全部移动完成要求弹出提示框显示拼图成功(提示框为id标记为success的div标签)
2. 如果在移动途中松开鼠标,则
  2.1 左侧拼图模块如果没有和目标位置发生重合,拼图模块需要回到原来的位置
  2.2 如果拼图模块和目标位置有2/3以上重合则认为拼图成功,此时拼图模块移动到目标位置,并且无法再次拖动
3. 在移动时鼠标需要一直在拼图模块上,否则拼图模块停止移动
4. 当前页面默认已经调用drag函数,请不要删除该调用语句
5. 请不要手动修改html和css
6. 不要使用第三方插件
7. 请使用ES5语法
function drag() {
   var success=document.getElementById("success");
   var srcs=[];
   // 给每一个源div加上isRight属性判断是否已经移动成功
   for (var i = 0; i < 3; i++) {
       srcs.push(document.getElementById("src-"+(i+1)))
       srcs[i].isRight=false;
   }
   // 获取div的宽和高
   var width=srcs[0].clientWidth;
   var height=srcs[0].clientHeight;
  

    for(var i=0;i<srcs.length;i++) {
        
        srcs[i].onmousedown=(function(i){
            return  function(event){
                var dest=document.getElementById("dest-"+(i+1));
                // 获得目标div的位置以及中心点位置
                var destX=dest.offsetLeft;
                var destY=dest.offsetTop;
                var destCenterX=dest.offsetLeft+width/2;
                var destCenterY=dest.offsetTop+height/2;
                var that=this;
                var event=event||window.event;
                var originX=that.offsetLeft;
                var originY=that.offsetTop;
                var disX=event.clientX-that.offsetLeft;
                var disY=event.clientY-that.offsetTop;

                document.onmousemove=function(e){
                    var e=e||window.event;
                    var iL=e.clientX-disX;
                    var iT=e.clientY-disY;

                    iL=(iL<0?0:iL);
                    iT=(iT<0?0:iT);
                    that.style.left=iL+"px";
                    that.style.top=iT+"px";
                }

                document.onmouseup=function(e){
                    document.onmousemove=null;
                    document.onmouseup=null;
                    // 获得当前移动的div的中心点位置
                    var srcCenterX=that.offsetLeft+width/2;
                    var srcCenterY=that.offsetTop+height/2;
                    // 比较源中心点的位置和目标中心点的位置的差的绝对值,如果距离小于三分之一的宽高,则表示移动的div已经覆盖了目标div的三分之二以上,此时可以重合
                    var distanceX=Math.abs(srcCenterX-destCenterX);
                    var distanceY=Math.abs(srcCenterY-destCenterY);
                    if(that.offsetLeft!==destX||that.offsetTop!==destY){
                        that.style.left=originX+"px";
                        that.style.top=originY+"px";
                    }
                    if((distanceX<=(width/3))&&(distanceY<=(height/3))){
                        that.style.left=destX+1+"px";
                        that.style.top=destY+1+"px";
                        that.isRight=true;
                        // 移动完成后不可以再移动
                        that.onmousedown=null;
                    }
                    if(srcs[0].isRight===true&&srcs[1].isRight===true&&srcs[2].isRight===true){
                        success.style.display="block";
                    }
                }
            
            }
        }(i))   
    }

}

发表于 2019-03-13 11:04:33 回复(0)
function drag() {
    var srcEle_1 = document.getElementById('src-1')
    var srcEle_2 = document.getElementById('src-2')
    var srcEle_3 = document.getElementById('src-3')
    var destEle_1 = document.getElementById('dest-1')
    var destEle_2 = document.getElementById('dest-2')
    var destEle_3 = document.getElementById('dest-3')
    var success = document.getElementById(('success'))
    var successNum = 0 //成功次数,三个都放上就弹出成功框
    function MoveEle(ele) { //移动元素对象
        this.ele = ele
        this.mouse = {
            mouseEleClient: { //鼠标距离该元素左上角的x和y距离
                t: 0,
                l: 0
            },
            mouseSuo: false //鼠标在元素上按下时,替换为true
        }
        this.isTarget = true //移动到目标位置永久锁住
        this.offsetLeft = ele.offsetLeft //原来位置
        this.offsetTop = ele.offsetTop //原来位置
    }
    MoveEle.prototype.init = function (fn) { //初始化移动元素
        var ele = this.ele
        var mouse = this.mouse
        var _this = this
        ele.onmousedown = function (e) {
            if (_this.isTarget) {
                e = e || window.event
                var l = e.clientX
                var t = e.clientY
                mouse.mouseEleClient.t = t - this.offsetTop
                mouse.mouseEleClient.l = l - this.offsetLeft
                mouse.mouseSuo = true
            }
        }
        ele.onmouseup = function (e) {
            mouse.mouseSuo = false
            fn(this.offsetTop, this.offsetLeft)
        }
        window.addEventListener('mousemove', function (e) {
            if (mouse.mouseSuo) {
                e = e || window.event
                var l = e.clientX
                var t = e.clientY
                ele.style.top = t - mouse.mouseEleClient.t + 'px'
                ele.style.left = l - mouse.mouseEleClient.l + 'px'
            }
        })
    }
    MoveEle.prototype.toTarget = function (left, top) { //移动到终点并固定
        this.ele.style.top = ++top + 'px'
        this.ele.style.left = ++left + 'px'
        this.isTarget = false //锁住元素无法移动了
    }
    MoveEle.prototype.toOrigin = function () { //移动到原来位置
        this.ele.style.top = this.offsetTop + 'px'
        this.ele.style.left = this.offsetLeft + 'px'
    }
    function TargetEle(ele) { //目标元素对象
        this.ele = ele
        this.target = {
            coincidence: 2 / 3, //连个元素重叠2/3就算成功
            isTarget: false //元素是否已经放上
        }
        this.offsetTop = ele.offsetTop
        this.offsetLeft = ele.offsetLeft
    }
    TargetEle.prototype.isTarget = function (t, l, w, h) { //判断是否放上了元素
        this.ele.offsetWidth
        var xdt = Math.abs(t - this.offsetTop)
        var xdl = Math.abs(l - this.offsetLeft)
        console.log(t, l)
        h = h || this.ele.offsetHeight
        w = w || this.ele.offsetWidth
        var tarh = this.ele.offsetHeight - xdt
        var tarw = this.ele.offsetWidth - xdl
        if ((tarh * tarw) / (h * w) > this.target.coincidence && tarh > 0 && tarw > 0) {
            this.target.isTarget = true
            return true
        }
        return false
    }
    /////////////////////////////
    var srcME_1 = new MoveEle(srcEle_1)
    var desTE_1 = new TargetEle(destEle_1)
    srcME_1.init(function (t, l) {
        if (desTE_1.isTarget(t, l)) {
            srcME_1.toTarget(desTE_1.offsetLeft, desTE_1.offsetTop)
            successNum++
            if (successNum == 3) successFn()
        }else{
            srcME_1.toOrigin()
        }

    })
    var srcME_2 = new MoveEle(srcEle_2)
    var desTE_2 = new TargetEle(destEle_2)
    srcME_2.init(function (t, l) {
        if (desTE_2.isTarget(t, l)) {
            srcME_2.toTarget(desTE_2.offsetLeft, desTE_2.offsetTop)
            successNum++
            if (successNum == 3) successFn()
        }else{
            srcME_2.toOrigin()
        }
    })
    var srcME_3 = new MoveEle(srcEle_3)
    var desTE_3 = new TargetEle(destEle_3)
    srcME_3.init(function (t, l) {
        if (desTE_3.isTarget(t, l)) {
            srcME_3.toTarget(desTE_3.offsetLeft, desTE_3.offsetTop)
            successNum++
            if (successNum == 3) successFn()
        }else{
            srcME_3.toOrigin()
        }

    })
    //成功
    function successFn() {
        success.style.display = 'block'
    }
}



编辑于 2019-03-12 19:56:33 回复(1)
用了es6语法 通过在线编译成es5 第6组用例不通过个 用例信息不全 本地无法测试
原版
function drag() {
    var cgNumber = 0, // 成功数量
        srcs = document.querySelectorAll('.src'),
        dests = document.querySelectorAll('.dest'),
        success = document.querySelector('#success'),
        // 目标位置信息
        destPos = [...dests].map(el => ({
            id: el.id,
            pos: el.getBoundingClientRect()
        })),
        // 拼图模块添加拖拽
        removeFunArr = [...srcs].map(src => ({
            id: src.id,
            pos: src.getBoundingClientRect(),
            remove: _drag(src)
        }));
    // 拖拽
    function _drag(el) {
        var isDrag = false, // 是否可拖拽
            startX = 0, // 鼠标距离盒子的距离
            startY = 0;
        function down(e) {
            isDrag = true
            startY = e.pageY - this.offsetTop
            startX = e.pageX - this.offsetLeft
        }
        function move(e) {
            if (!isDrag) return;
            // 当前位置 - 鼠标局里盒子位置
            moveDom(this, e.pageY - startY, e.pageX - startX)
        }
        function closehandler(e) {
            isDrag = false
            handler(this)
        }
        el.addEventListener('mousedown', down)
        el.addEventListener('mouseup', closehandler)
        el.addEventListener('mouseleave', closehandler)
        el.addEventListener('mousemove', move)
        function removeEvent() {
            el.removeEventListener('mousedown', down)
            el.removeEventListener('mouseup', closehandler)
            el.removeEventListener('mouseleave', closehandler)
            el.removeEventListener('mousemove', move)
        }
        return removeEvent
    }
    function moveDom(el, top, left) {
        el.style.top = top + 'px'
        el.style.left = left + 'px'
    }
    // 判断位置及后续处理
    function handler(el) {
        var id = el.id.replace('src', 'dest')
        // 对应目标位置
        var targetPos = destPos.find(pos => pos.id == id)
        // 判断是否到目标区域 2/3以上重合
        if (targetPos) {
            // 区域设置 目标位置 4周全部加 1/3 距离 在该区域内即可
            var tarPos = targetPos.pos
            var offsetY = tarPos.height / 3
            var offsetX = tarPos.width / 3
            var pos = {
                width: tarPos.width + offsetX * 2,
                height: tarPos.height + offsetY * 2,
                top: tarPos.top - offsetY,
                left: tarPos.left - offsetX
            }
            if (
                el.offsetLeft >= pos.left &&
                el.offsetLeft <= pos.left + pos.width &&
                el.offsetTop >= pos.top &&
                el.offsetTop <= pos.top + pos.height
            ) {
                console.log('拼图成功')
                sucessHandle(el, { // 拼图成功处理
                    left: tarPos.left + 1,
                    top: tarPos.top + 1
                })
            }else{
                console.log('拼图失败')
                rejecthander(el)
            }
        }
    }
    function rejecthander(el){
        var obj = removeFunArr.find(obj => obj.id == el.id)
        obj && moveDom(el, obj.pos.top, obj.pos.left)
    }
    function sucessHandle(el, {
        top,
        left
    }) {
        // 移动到目标位置
        moveDom(el, top, left)
        // 取消移动
        var obj = removeFunArr.find(obj => obj.id == el.id)
        obj && obj.remove();
        cgNumber++
        if (cgNumber == srcs.length) { // 全部完成
            success.style.display = 'block'
        }
    }
}

编译后
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }

function drag() {

    var cgNumber = 0,
        // 成功数量
    srcs = document.querySelectorAll('.src'),
        dests = document.querySelectorAll('.dest'),
        success = document.querySelector('#success'),

    // 目标位置信息
    destPos = [].concat(_toConsumableArray(dests)).map(function (el) {
        return {
            id: el.id,
            pos: el.getBoundingClientRect()
        };
    }),

    // 拼图模块添加拖拽
    removeFunArr = [].concat(_toConsumableArray(srcs)).map(function (src) {
        return {
            id: src.id,
            pos: src.getBoundingClientRect(),
            remove: _drag(src)
        };
    });

    // 拖拽
    function _drag(el) {
        var isDrag = false,
            // 是否可拖拽
        startX = 0,
            // 鼠标距离盒子的距离
        startY = 0;

        function down(e) {
            isDrag = true;
            startY = e.pageY - this.offsetTop;
            startX = e.pageX - this.offsetLeft;
        }

        function move(e) {
            if (!isDrag) return;
            // 当前位置 - 鼠标局里盒子位置
            moveDom(this, e.pageY - startY, e.pageX - startX);
        }

        function closehandler(e) {
            isDrag = false;
            handler(this);
        }
        el.addEventListener('mousedown', down);
        el.addEventListener('mouseup', closehandler);
        el.addEventListener('mouseleave', closehandler);
        el.addEventListener('mousemove', move);

        function removeEvent() {
            el.removeEventListener('mousedown', down);
            el.removeEventListener('mouseup', closehandler);
            el.removeEventListener('mouseleave', closehandler);
            el.removeEventListener('mousemove', move);
        }
        return removeEvent;
    }

    function moveDom(el, top, left) {
        el.style.top = top + 'px';
        el.style.left = left + 'px';
    }
    // 判断位置及后续处理
    function handler(el) {
        var id = el.id.replace('src', 'dest');
        // 对应目标位置
        var targetPos = destPos.find(function (pos) {
            return pos.id == id;
        });
        // 判断是否到目标区域 2/3以上重合
        if (targetPos) {
            // 区域设置 目标位置 4周全部加 1/3 距离 在该区域内即可
            var tarPos = targetPos.pos;
            var offsetY = tarPos.height / 3;
            var offsetX = tarPos.width / 3;
            var pos = {
                width: tarPos.width + offsetX * 2,
                height: tarPos.height + offsetY * 2,
                top: tarPos.top - offsetY,
                left: tarPos.left - offsetX
            };
            if (el.offsetLeft >= pos.left && el.offsetLeft <= pos.left + pos.width && el.offsetTop >= pos.top && el.offsetTop <= pos.top + pos.height) {
                console.log('拼图成功');
                sucessHandle(el, { // 拼图成功处理
                    left: tarPos.left + 1,
                    top: tarPos.top + 1
                });
            } else {
                console.log('拼图失败');
                rejecthander(el);
            }
        }
    }

    function rejecthander(el) {
        var obj = removeFunArr.find(function (obj) {
            return obj.id == el.id;
        });
        obj && moveDom(el, obj.pos.top, obj.pos.left);
    }
    function sucessHandle(el, _ref) {
        var top = _ref.top;
        var left = _ref.left;

        // 移动到目标位置
        moveDom(el, top, left);
        // 取消移动
        var obj = removeFunArr.find(function (obj) {
            return obj.id == el.id;
        });
        obj && obj.remove();
        cgNumber++;
        if (cgNumber == srcs.length) {
            // 全部完成
            success.style.display = 'block';
        }
    }
}

发表于 2021-06-29 12:07:09 回复(0)
drag();


// 可能被用到的一些点 
// element.style.top element.style.left
// element.offsetTop element.offsetLeft
// Math.abs
// document.body.onmouseup
// document.body.onmouseleave
function drag() {
var aSrc = document.querySelectorAll('.src')
var count = 0
aSrc.forEach(src => {
    src.onmousedown = function(e){
            var tag = src.getAttribute('id').replace(/^src-/,'')
            var dest = document.querySelector(`#dest-${tag}`)
            var dest_top = dest.offsetTop + 1
            var dest_left = dest.offsetLeft + 1

            var width = src.offsetWidth

            var top = src.offsetTop
            var left = src.offsetLeft

            var lenx = e.clientX - left
            var leny = e.clientY - top
            // console.log(lenx,leny)
            var src_top = null
            var src_left = null
        src.onmousemove = function(e){
            src_top = e.clientY - leny
            src_left = e.clientX - lenx
   
            src.style.top = src_top + 'px'
            src.style.left = src_left + 'px'

            if(isMerge(src_left,src_top,dest_left,dest_top,width)){
                src.style.top = dest_top + 'px'
                src.style.left = dest_left + 'px'
                src.onmousedown = src.onmouseleave = src.onmouseup = src.onmousemove = null
                count += 1
                if(count == 3){
                    document.querySelector('#success').style.display = 'block'
                }
            }
        }
        src.onmouseup = function(e){
            src.onmouseleave = src.onmouseup = src.onmousemove = null
            if(src.offsetTop !== dest_top || src.offsetLeft !== dest_left){
                src.style.top = top + 'px'
                src.style.left = left + 'px'
            }
        }
        src.onmouseleave = function(e){
            src.onmouseleave = src.onmouseup = src.onmousemove = null
        }
    }


})

function isMerge(src_left,src_top,dest_left,dest_top,width){
    var left = src_left - dest_left
    var top = src_top - dest_top
    if(Math.abs(left) <= width || Math.abs(top) <= width){
        if(((width-Math.abs(left))*(width-Math.abs(top)))/(width*width) >= 2/3 ){
            return true
        } else {
            return false
        }
    }else {
        return false
    }
}
}
不知道为啥通不过
发表于 2021-06-07 15:03:58 回复(0)
在自己电脑上测试没问题,在这里通过不了
复制测试代码到写的代码中控制台也是true啊,测试框那里是false
编辑于 2021-05-16 15:53:19 回复(0)
function drag() { var disX,disY = 0; 
 var isSuccess = 0;  
$('.src').mousedown(function(ev){ 
var startLeft = $(this).css('left'); 
 var startTop = $(this).css('top'); 
 ev = ev||event; 
 disX = ev.clientX - this.offsetLeft; 
 disY = ev.clientY - this.offsetTop; 
 var self = this;  document.onmousemove = function(ev){
            self.style.left = ev.clientX - disX + 'px';  
self.style.top = ev.clientY - disY + 'px';  }
        document.onmouseup = function(){
            document.onmousemove = null;  document.onmouseup = null; 
 var num = self.innerHTML; 
 var dest = document.getElementById(`dest-${num}`);  
var destLeft = document.body.clientWidth -parseFloat(window.getComputedStyle(dest,null).right)-50; 
 var destTop= parseFloat(window.getComputedStyle(dest,null).top); 
 if(Math.abs(destLeft-parseFloat($(self).css('left')))16.7&&Math.abs(destTop- parseFloat($(self).css('top')))16.7)
{
                self.style.left = destLeft -1+ 'px'; 
 self.style.top = destTop+1 + 'px'; 
 $(self).off('mousedown'); //解绑 
 isSuccess++; 
 if(isSuccess===3){
                     document.getElementById('success').style.display = 'block';  }
             }else{
                 self.style.left = startLeft;  self.style.top = startTop;  }
        }
    })
}

编辑于 2019-04-22 21:15:23 回复(0)