• 模拟拖拽图片 碰撞检测 DOM 鼠标事件 闭包


    <!doctype html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="Generator" content="EditPlus®">
    <meta name="Author" content="">
    <meta name="Keywords" content="">
    <meta name="Description" content="">
    <title>图片拖拽</title>
    <style type="text/css">
    body,ul{
    margin:0px;
    padding:0px;
    }
    .box{
    position:relative;
    380px;
    height:380px;
    margin:100px auto;
    border:1px solid black;
    }
    .box ul li{
    margin:20px 0 0 20px;
    100px;
    height:100px;
    list-style:none;
    float:left;
    }
    .box ul li img{
    display:inline-block;
    }
    </style>
    </head>
    <body>
    <div class="box">
    <ul class="imgWrapper">
    <li><img src="1.jpg" alt="" width="100px" height="100px" /></li>
    <li><img src="2.jpg" alt="" width="100px" height="100px" /></li>
    <li><img src="3.jpg" alt="" width="100px" height="100px" /></li>
    <li><img src="4.jpg" alt="" width="100px" height="100px" /></li>
    <li><img src="5.jpg" alt="" width="100px" height="100px" /></li>
    <li><img src="6.jpg" alt="" width="100px" height="100px" /></li>
    <li><img src="7.jpg" alt="" width="100px" height="100px" /></li>
    <li><img src="8.jpg" alt="" width="100px" height="100px" /></li>
    <li><img src="9.jpg" alt="" width="100px" height="100px" /></li>
    </ul>
    </div>

    <script type="text/javascript">

    //全局变量一定要少定义
    //容易出错 还占内存

    /*图标拖拽
    1.如果想让图标移动 那就得把浮动布局改为浮动布局
    1.1
    操作系统和浏览器是多线程(伪多线程)
    是在非常短的时间内执行单个线程比如1um
    比如一秒内就可以完成多个单线程
    而JS是单线程
    当四个任务让浏览器执行的时候
    因为是单线程 谁执行快返回谁
    所以 写的代码有的时候和返回的而结果不一样

    2.当鼠标点住一张图片的时候 图片可以拖动(鼠标移动)
    2.1事件代理 点击事件 //有点行不通
    2.1 onmousedown onmousemove onmouseup
    循环给每个li元素加上
    2.2 记录点击的那个位置 两次鼠标位置相减 加上自身偏移量 都会改变left top值
    让图片跟着鼠标走

    3.在拖动图片的时候碰撞检测

    3.1 计算与周围的图标的距离 距离最短的那个图片添加border
    3.2如果没有检测到 则松开鼠标的时候 图片回到原始位置
    3.3当松开鼠标的时候 图片位置平滑交换
    3.4
    */


    //获取元素的时候 不是数组 要转化为数组 或者 把所需要的内容添加到自定义数组中
    var liList=document.querySelectorAll(".box ul li ");//伪数组
    var imgWrapper=document.querySelector(".imgWrapper");
    var nearElement=null;
    var arr=Array.prototype.slice.call(liList);
    var liPos=[];
    var sign=[];
    var num=1;
    var control=false;


    function deleteBorder(arr){

    for(var i=0,item;item=arr[i++];){

    arr[i-1].style.border="";

    }

    }

    function pos(){

    /*设置比获取速度要快
    如果想让设置之在获取之后就要让他的执行速度变慢
    可以用定时器 定时器 要注意闭包作用域的问题
    函数立执行
    */

    for( var j=0,len=arr.length;j<len;j++){

    liPos.push([arr[j].offsetLeft,arr[j].offsetTop]);
    //函数自执行
    (function(n){
    setTimeout(function(){
    arr[n].style.position="absolute"; //把浮动改成定位
    arr[n].style.left=liPos[n][0]+"px"; //重新设置位置
    arr[n].style.top=liPos[n][1]+"px";
    arr[n].style.margin="0";//margin设置为0 不然会有两个margin距离
    },0);
    })(j);

    }
    }
    pos();

    //mousedown mouseover mouseup
    //给每个li添加事件
    for(var i=0,item;item=arr[i++];){
    //给元素添加index属性
    arr[i-1].index=i-1;
    drag(arr[i-1]);

    }
    //拖拽
    function drag(obj){

    obj.onmousedown=function(e){
    e.preventDefault();
    var oldX=e.offsetX;
    var oldY=e.offsetY;
    ++num;
    obj.style.zIndex=num;

    obj.onmousemove=function(e){

    var newX=e.offsetX;
    var newY=e.offsetY;

    obj.style.left=(newX-oldX+obj.offsetLeft)+"px";
    obj.style.top=(newY-oldY+obj.offsetTop)+"px";
    for(var i=0,len=arr.length;i<len;i++){
    if(!impact(obj,arr[i])&&obj!=arr[i]){
    if(!impact(obj,arr[i])){

    //记录下碰撞成功的元素
    sign.push(arr[i]);
    }
    else{
    //没有碰撞的话元素边框消失
    arr[i].style.border="";
    }

    }
    }

    //在碰撞中的元素中找到最短的那个设置边框
    if(!(sign&&sign.length==0)){// 当sign数组里面没有元素的时候不执行
    nearElement=nearDistance(obj,sign);
    nearElement.style.border="1px solid red"
    }

    }

    }
    //鼠标抬起 平滑交换位置 动画
    obj.onmouseup=function(){
    obj.onmousemove=null;

    if(!(sign&&sign.length==0)){

    move(obj,[liPos[obj.index][0],liPos[obj.index][1]],[liPos[nearElement.index][0],liPos[nearElement.index][1]]);
    move(nearElement,[liPos[nearElement.index][0],liPos[nearElement.index][1]],[liPos[obj.index][0],liPos[obj.index][1]]);

    deleteBorder(arr);
    //交换完之后 index 交换
    var index=nearElement.index;
    nearElement.index=obj.index;
    obj.index=index;
    //全局变量一定要注意
    sign=[];

    }
    else{
    obj.style.left=liPos[obj.index][0]+"px";
    obj.style.top=liPos[obj.index][1]+"px";
    }
    }

    }

    //碰撞检测
    function impact(obj1,obj2){

    var L1=obj1.offsetLeft;
    var T1=obj1.offsetTop;
    var R1=L1+obj1.offsetWidth;
    var B1=T1+obj1.offsetHeight;

    var L2=obj2.offsetLeft;
    var T2=obj2.offsetTop;
    var R2=L2+obj2.offsetWidth;
    var B2=T2+obj2.offsetHeight;

    if(L1>R2||R1<L2||T1>B2||B1<T2){//满足其中任和一个 都不可能碰撞

    return true;

    }
    else{
    return false;
    }

    }

    //判断最短距离
    function nearDistance(obj,arr){
    //第一个数组里面保存的事li元素 第二个保存的是斜边长度
    //根据对应的斜边长度找到对应的元素
    var value=[[],[]];
    for(var i=0,len=arr.length;i<len;i++){
    //勾股定理

    var a=arr[i].offsetLeft-obj.offsetLeft;
    var b=arr[i].offsetTop-obj.offsetTop;
    //计算最短斜边
    value[0].push(arr[i]);
    value[1].push(Math.sqrt(a*a+b*b));
    }

    //返回最小斜边对应的那个li元素 设置边框之前其他的边框清除 然后设置碰撞最短元素边框
    deleteBorder(arr);
    //这段代码可读性不太好
    return value[0][value[1].indexOf(Math.min.apply(Math,value[1]))];
    }

    //事件运动函数
    function move(obj,current,target){
    //X,Y轴都会变化

    //时间运动公式 s=t*S/T
    var T=500;
    var t=new Date();
    var Sx=target[0]-current[0];
    var Sy=target[1]-current[1];
    var timer=null;
    var stepX=0,stepY=0;
    var changeTime=0;
    //var currentX=0,currentY=0;
    timer=setInterval(function(){
    changeTime=new Date()-t;
    //currentX=obj.offsetLeft;
    //currentY=obj.offsetTop;
    if(changeTime/T>=1){
    clearInterval(timer);
    obj.style.left=target[0]+"px";
    obj.style.top=target[1]+"px";
    }
    else{

    stepX=parseInt(changeTime*Sx/T);
    stepY=parseInt(changeTime*Sy/T);
    obj.style.left=current[0]+stepX+"px";
    obj.style.top=current[1]+stepY+"px";
    }

    },1000/60);




    }

    </script>
    </body>
    </html>

  • 相关阅读:
    对话框中获取Month Calendar的当前日期
    JAVA GUI程序示例
    MFC控件显示值和控件变量值的更新
    JAVA求10到99的随机数
    学习之路二:关于集合和数组内在联系的深入了解
    迭代器学习之三:IEnumerable和IEnumerator的泛型结构
    迭代器学习之四:关于yield的深入了解
    迭代器学习之二:数组的可枚举类型和枚举数的定义以及编译器的foreach工作原理
    学习之路三:关于运用单线程和委托以及事件自定义Timer类
    迭代器学习之一:使用IEnumerable和IEnumerator接口
  • 原文地址:https://www.cnblogs.com/liveoutfun/p/9094676.html
Copyright © 2020-2023  润新知