Vue实现拖拽升级(九宫格拖拽)

感谢参考原文-http://bjbsair.com/2020-03-27/tech-info/7202.html

基于Vue实现拖拽升级(九宫格拖拽)

前言

在本文中将会用Vue完成九宫格拖拽效果,同时介绍一下网格布局。具体代码以及demo可以点以下超链接进入

效果实例

基于Vue实现拖拽升级(九宫格拖拽)

Demo

简单了解Grid布局(网格布局)

什么是网格布局

CSS网格布局(又称“网格”),是一种二维网格布局系统。CSS在处理网页布局方面一直做的不是很好。一开始我们用的是table(表格)布局,然后用float(浮动),position(定位)和inline-block(行内块)布局,但是这些方法本质上是hack,遗漏了很多功能,例如垂直居中。后来出了flexbox(盒子布局),解决了很多布局问题,但是它仅仅是一维布局,而不是复杂的二维布局,实际上它们(flexbox与grid)能很好的配合使用。Grid布局是第一个专门为解决布局问题而创建的CSS模块.

基于Vue实现拖拽升级(九宫格拖拽)

grid

简单说说网格布局的属性

  • display: grid: 生成块级网格 inline-grid: 生成行内网格 subgrid: 如果网格容器本身是网格项(嵌套网格容器),此属性用来继承其父网格容器的列、行大小。
  • grid-template-columns 设置网格列大小
  • grid-template-rows 设置网格行大小
  • grid-template-areas 设置网格区域
  • grid-column-gap 设置网格列间距
  • grid-row-gap 设置网格行间距
  • grid-gap 缩写形式 grid-gap: <grid-row-gap> <grid-column-gap>
  • justify-items 水平方向对齐方式(在这里只是简单说明) start: 左对齐 end: 右对齐 center: 居中对齐 stretch: 填满(默认)
  • align-items 垂直方向对齐方式 start: 顶部对齐 end: 底部对齐 center: 居中对齐 stretch:填满(默认)

当然,如果看不懂也不要紧,这里有一篇个人十分喜欢的网格布局的文章。里面介绍得十分详细。可以供大家深入学习网格布局内容。

传送门:Grid布局指南

https://www.jianshu.com/p/d183265a8dad

实现九宫格布局

/*css*/  
  
  .container{  
    position: relative;   /*实现定位,使得滑块定位相对于此*/  
    display: grid;        /*定义网格布局*/  
    width: 300px;  
    height: 300px;  
    grid-template-columns: 100px 100px 100px;     /*实现九宫格,行列各三*/  
    grid-template-rows: 100px 100px 100px;  
    grid-template-areas: "head1 head2 head3"      /*定义个格子的名称,方便计算*/  
                          "main1 main2 main3"  
                          "footer1 footer2 footer3";  
    border: 1px solid #000;  
    margin: 0 auto;  
  }  
  .block{  
    position: absolute;     /*相对于container定位*/  
    width: 100px;  
    height: 100px;  
    display: flex;        /*flex布局,使得文字在中央*/  
    justify-content: center;  
    justify-items: center;  
    align-items: center;  
    align-content: center;  
    user-select: none;      /*用户不可选定文字*/  
    background: olivedrab;  
    border: 1px solid #000  
  }  

//app.vue  
  
<div id="app">  
  <div class="container">  
    <transition >  
      <div class="block animated"  :style="{top:this.positionY,left:this.positionX,gridArea:'main2'}" @mousedown="move" ref="block">  
        {{positionX}}  
        {{positionY}}  
      </div>  
    </transition>  
  </div>  
</div>  

实现拖拽的JS代码部分

在这里我选取一些核心代码出来讲解。代码有所省略,因为代码着实有点长,太占篇幅而且没多大意义,如果需要浏览全部代码可以点击上面的Demo连接。

<script>  
//引入animate.css 没有手撕css动画,直接用了animate.css实现我们的动画效果  
import animate from 'animate.css';  
  
export default {  
  name: 'app',  
  data () {  
    return {  
      positionX:0,      //定义方块的两个坐标  
      positionY:0,  
    }  
  },  
  methods:{  
    move(e){  
      let oDiv = e.target;      //获取点击的目标元素  
      let gDiv = e.path[1];     //获取点击元素的父级元素  
        
      /*获取点击时的偏移位置,在这里要注意一下  
      **由于我们用的是网格布局,每在一个格子中相对位置都是相对格子来算的,不是相对于父级盒子左上角  
      **也就是说当你把方块移动到九个格子中任意一个时,方块的位置都是top:0和left:0  
      */  
        
      //所以这里我们直接取鼠标点击的位置减去点击盒子的偏移位置,也就是0  
      let disX = e.clientX - 0;       
      let disY = e.clientY - 0;  
      document.onmousemove = (e)=>{  
        
        //当拖动时,算出的值就刚好是方块的top和left值  
        let left = e.clientX - disX;  
        let top = e.clientY - disY;  
        switch (oDiv.style.gridArea){  
          case "head1 / head1 / head1 / head1":this.rangeOfHead1(left,top,oDiv);break;    //实现head1的移动范围  
          case "head2 / head2 / head2 / head2":this.rangeOfHead2(left,top,oDiv);break;    //实现head2的移动范围  
          case "head3 / head3 / head3 / head3":this.rangeOfHead3(left,top,oDiv);break;    //实现head3的移动范围  
          case "main1 / main1 / main1 / main1":this.rangeOfMain1(left,top,oDiv);break;    //实现main1的移动范围  
          ...  
        }  
      };  
      document.onmouseup = (e)=>{  
        //当鼠标抬起时,我们要做的事  
        //通过点击位置和父级元素的偏移判断方块在哪个区域  
        if(e.clientY-gDiv.offsetTop<100&&e.clientX-gDiv.offsetLeft<100){  
          
          //将方块移动到该区域中  
          this.changeBlock("head1",oDiv);   
            
        }else if(e.clientY-gDiv.offsetTop>100&&e.clientX-gDiv.offsetLeft<100&&e.clientY-gDiv.offsetTop<200){  
          this.changeBlock("main1",oDiv);  
        }else if(e.clientY-gDiv.offsetTop>200&&e.clientX-gDiv.offsetLeft<100){  
          this.changeBlock("footer1",oDiv);  
        }else if(e.clientY-gDiv.offsetTop<100&&e.clientX-gDiv.offsetLeft>100&&e.clientX-gDiv.offsetLeft<200){  
          this.changeBlock("head2",oDiv);  
        }else if(e.clientY-gDiv.offsetTop<100&&e.clientX-gDiv.offsetLeft>200){  
          this.changeBlock("head3",oDiv);  
        }else if(e.clientY-gDiv.offsetTop>100&&e.clientX-gDiv.offsetLeft>200&&e.clientY-gDiv.offsetTop<200){  
          this.changeBlock("main3",oDiv);  
        }else if(e.clientY-gDiv.offsetTop>200&&e.clientX-gDiv.offsetLeft>200){  
          this.changeBlock("footer3",oDiv);  
        }else if(e.clientY-gDiv.offsetTop>200&&e.clientX-gDiv.offsetLeft>100&&e.clientX-gDiv.offsetLeft<200){  
          this.changeBlock("footer2",oDiv);  
        }else {  
          this.changeBlock("main2",oDiv);  
        }  
        document.onmousemove=null;      //需要把事件监听取消  
        document.onmousedown = null;    //需要把事件监听取消  
          
        //当然,不能忘记我们的动画hhh  
        oDiv.className = "block animated wobble";  
        let removeClass = setTimeout(()=>{  
          oDiv.className = "block animated";  
        },500);  
  
      };  
    },  
    rangeOfHead1(x,y,oDiv){     //判断head1格子中的可以移动范围  
      if(x>=200){  
        x=200;  
      }else if(x<=0){  
        x=0;  
      }  
      if(y>=200){  
        y=200;  
      }else if(y<=0){  
        y=0;  
      }  
      oDiv.style.left = x + 'px';  
      oDiv.style.top = y + 'px';  
      this.positionX = x;  
      this.positionY = y;  
  
    },  
    rangeOfHead2(x,y,oDiv){     //判断head2格子中的可以移动范围  
      if(x>=100){  
        x=100;  
      }else if(x<=-100){  
        x=-100;  
      }  
      if(y>=200){  
        y=200;  
      }else if(y<=0){  
        y=0;  
      }  
      oDiv.style.left = x + 'px';  
      oDiv.style.top = y + 'px';  
  
      this.positionX = x;  
      this.positionY = y;  
  
    },  
    ...  
    changeBlock(blockName,oDiv){    //将方块移入到对应的区域中  
      this.positionX = 0;  
      this.positionY = 0;  
      oDiv.style.gridArea=blockName;  
    }  
  },  
}  
</script>  

总结

到这里我们把九宫格拖拽实现了,同时学习了Grid(网格布局)。总的做下来,发现用网格布局做网格拖拽更加费事,但是为了后续可以方便一些,也只好捣鼓下来了。到这里我们就把基于Vue的九宫格拖拽实现了,有问题或者发现错误的请指正,谢谢大家

珍惜淡定的心境,苦过后更加清感谢参考原文-http://bjbsair.com/2020-03-27/tech-info/7202/

基于Vue实现拖拽升级(九宫格拖拽)

前言

在本文中将会用Vue完成九宫格拖拽效果,同时介绍一下网格布局。具体代码以及demo可以点以下超链接进入

效果实例

基于Vue实现拖拽升级(九宫格拖拽)

Demo

简单了解Grid布局(网格布局)

什么是网格布局

CSS网格布局(又称“网格”),是一种二维网格布局系统。CSS在处理网页布局方面一直做的不是很好。一开始我们用的是table(表格)布局,然后用float(浮动),position(定位)和inline-block(行内块)布局,但是这些方法本质上是hack,遗漏了很多功能,例如垂直居中。后来出了flexbox(盒子布局),解决了很多布局问题,但是它仅仅是一维布局,而不是复杂的二维布局,实际上它们(flexbox与grid)能很好的配合使用。Grid布局是第一个专门为解决布局问题而创建的CSS模块.

基于Vue实现拖拽升级(九宫格拖拽)

grid

简单说说网格布局的属性

  • display: grid: 生成块级网格 inline-grid: 生成行内网格 subgrid: 如果网格容器本身是网格项(嵌套网格容器),此属性用来继承其父网格容器的列、行大小。
  • grid-template-columns 设置网格列大小
  • grid-template-rows 设置网格行大小
  • grid-template-areas 设置网格区域
  • grid-column-gap 设置网格列间距
  • grid-row-gap 设置网格行间距
  • grid-gap 缩写形式 grid-gap: <grid-row-gap> <grid-column-gap>
  • justify-items 水平方向对齐方式(在这里只是简单说明) start: 左对齐 end: 右对齐 center: 居中对齐 stretch: 填满(默认)
  • align-items 垂直方向对齐方式 start: 顶部对齐 end: 底部对齐 center: 居中对齐 stretch:填满(默认)

当然,如果看不懂也不要紧,这里有一篇个人十分喜欢的网格布局的文章。里面介绍得十分详细。可以供大家深入学习网格布局内容。

传送门:Grid布局指南

https://www.jianshu.com/p/d183265a8dad

实现九宫格布局

/*css*/  
  
  .container{  
    position: relative;   /*实现定位,使得滑块定位相对于此*/  
    display: grid;        /*定义网格布局*/  
    width: 300px;  
    height: 300px;  
    grid-template-columns: 100px 100px 100px;     /*实现九宫格,行列各三*/  
    grid-template-rows: 100px 100px 100px;  
    grid-template-areas: "head1 head2 head3"      /*定义个格子的名称,方便计算*/  
                          "main1 main2 main3"  
                          "footer1 footer2 footer3";  
    border: 1px solid #000;  
    margin: 0 auto;  
  }  
  .block{  
    position: absolute;     /*相对于container定位*/  
    width: 100px;  
    height: 100px;  
    display: flex;        /*flex布局,使得文字在中央*/  
    justify-content: center;  
    justify-items: center;  
    align-items: center;  
    align-content: center;  
    user-select: none;      /*用户不可选定文字*/  
    background: olivedrab;  
    border: 1px solid #000  
  }  

//app.vue  
  
<div id="app">  
  <div class="container">  
    <transition >  
      <div class="block animated"  :style="{top:this.positionY,left:this.positionX,gridArea:'main2'}" @mousedown="move" ref="block">  
        {{positionX}}  
        {{positionY}}  
      </div>  
    </transition>  
  </div>  
</div>  

实现拖拽的JS代码部分

在这里我选取一些核心代码出来讲解。代码有所省略,因为代码着实有点长,太占篇幅而且没多大意义,如果需要浏览全部代码可以点击上面的Demo连接。

<script>  
//引入animate.css 没有手撕css动画,直接用了animate.css实现我们的动画效果  
import animate from 'animate.css';  
  
export default {  
  name: 'app',  
  data () {  
    return {  
      positionX:0,      //定义方块的两个坐标  
      positionY:0,  
    }  
  },  
  methods:{  
    move(e){  
      let oDiv = e.target;      //获取点击的目标元素  
      let gDiv = e.path[1];     //获取点击元素的父级元素  
        
      /*获取点击时的偏移位置,在这里要注意一下  
      **由于我们用的是网格布局,每在一个格子中相对位置都是相对格子来算的,不是相对于父级盒子左上角  
      **也就是说当你把方块移动到九个格子中任意一个时,方块的位置都是top:0和left:0  
      */  
        
      //所以这里我们直接取鼠标点击的位置减去点击盒子的偏移位置,也就是0  
      let disX = e.clientX - 0;       
      let disY = e.clientY - 0;  
      document.onmousemove = (e)=>{  
        
        //当拖动时,算出的值就刚好是方块的top和left值  
        let left = e.clientX - disX;  
        let top = e.clientY - disY;  
        switch (oDiv.style.gridArea){  
          case "head1 / head1 / head1 / head1":this.rangeOfHead1(left,top,oDiv);break;    //实现head1的移动范围  
          case "head2 / head2 / head2 / head2":this.rangeOfHead2(left,top,oDiv);break;    //实现head2的移动范围  
          case "head3 / head3 / head3 / head3":this.rangeOfHead3(left,top,oDiv);break;    //实现head3的移动范围  
          case "main1 / main1 / main1 / main1":this.rangeOfMain1(left,top,oDiv);break;    //实现main1的移动范围  
          ...  
        }  
      };  
      document.onmouseup = (e)=>{  
        //当鼠标抬起时,我们要做的事  
        //通过点击位置和父级元素的偏移判断方块在哪个区域  
        if(e.clientY-gDiv.offsetTop<100&&e.clientX-gDiv.offsetLeft<100){  
          
          //将方块移动到该区域中  
          this.changeBlock("head1",oDiv);   
            
        }else if(e.clientY-gDiv.offsetTop>100&&e.clientX-gDiv.offsetLeft<100&&e.clientY-gDiv.offsetTop<200){  
          this.changeBlock("main1",oDiv);  
        }else if(e.clientY-gDiv.offsetTop>200&&e.clientX-gDiv.offsetLeft<100){  
          this.changeBlock("footer1",oDiv);  
        }else if(e.clientY-gDiv.offsetTop<100&&e.clientX-gDiv.offsetLeft>100&&e.clientX-gDiv.offsetLeft<200){  
          this.changeBlock("head2",oDiv);  
        }else if(e.clientY-gDiv.offsetTop<100&&e.clientX-gDiv.offsetLeft>200){  
          this.changeBlock("head3",oDiv);  
        }else if(e.clientY-gDiv.offsetTop>100&&e.clientX-gDiv.offsetLeft>200&&e.clientY-gDiv.offsetTop<200){  
          this.changeBlock("main3",oDiv);  
        }else if(e.clientY-gDiv.offsetTop>200&&e.clientX-gDiv.offsetLeft>200){  
          this.changeBlock("footer3",oDiv);  
        }else if(e.clientY-gDiv.offsetTop>200&&e.clientX-gDiv.offsetLeft>100&&e.clientX-gDiv.offsetLeft<200){  
          this.changeBlock("footer2",oDiv);  
        }else {  
          this.changeBlock("main2",oDiv);  
        }  
        document.onmousemove=null;      //需要把事件监听取消  
        document.onmousedown = null;    //需要把事件监听取消  
          
        //当然,不能忘记我们的动画hhh  
        oDiv.className = "block animated wobble";  
        let removeClass = setTimeout(()=>{  
          oDiv.className = "block animated";  
        },500);  
  
      };  
    },  
    rangeOfHead1(x,y,oDiv){     //判断head1格子中的可以移动范围  
      if(x>=200){  
        x=200;  
      }else if(x<=0){  
        x=0;  
      }  
      if(y>=200){  
        y=200;  
      }else if(y<=0){  
        y=0;  
      }  
      oDiv.style.left = x + 'px';  
      oDiv.style.top = y + 'px';  
      this.positionX = x;  
      this.positionY = y;  
  
    },  
    rangeOfHead2(x,y,oDiv){     //判断head2格子中的可以移动范围  
      if(x>=100){  
        x=100;  
      }else if(x<=-100){  
        x=-100;  
      }  
      if(y>=200){  
        y=200;  
      }else if(y<=0){  
        y=0;  
      }  
      oDiv.style.left = x + 'px';  
      oDiv.style.top = y + 'px';  
  
      this.positionX = x;  
      this.positionY = y;  
  
    },  
    ...  
    changeBlock(blockName,oDiv){    //将方块移入到对应的区域中  
      this.positionX = 0;  
      this.positionY = 0;  
      oDiv.style.gridArea=blockName;  
    }  
  },  
}  
</script>  

总结

到这里我们把九宫格拖拽实现了,同时学习了Grid(网格布局)。总的做下来,发现用网格布局做网格拖拽更加费事,但是为了后续可以方便一些,也只好捣鼓下来了。到这里我们就把基于Vue的九宫格拖拽实现了,有问题或者发现错误的请指正,谢谢大家

珍惜淡定的心境,苦过后更加清

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,045评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,114评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,120评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,902评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,828评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,132评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,590评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,258评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,408评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,335评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,385评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,068评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,660评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,747评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,967评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,406评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,970评论 2 341

推荐阅读更多精彩内容

  • 前言 在本文中将会用Vue完成九宫格拖拽效果,同时介绍一下网格布局。具体代码以及demo可以点以下超链接进入 传送...
    bb7bb阅读 6,945评论 5 25
  • 效果实例 简单了解Grid布局(网格布局) 什么是网格布局 CSS网格布局(又称“网格”),是一种二维网格布局系统...
    他方l阅读 260评论 0 0
  • 效果实例 简单了解Grid布局(网格布局) 什么是网格布局 CSS网格布局(又称“网格”),是一种二维网格布局系统...
    HeroXin阅读 294评论 0 1
  • 简介CSS网格布局(又称“网格”),是一种二维网格布局系统。CSS在处理网页布局方面一直做的不是很好。一开始我们用...
    _leonlee阅读 64,863评论 25 173
  • 简介 CSS网格布局(又名“网格”)是一个二维的基于网格的布局系统,其目的只在于完全改变我们设计基于网格的用户界面...
    礼知白阅读 660评论 0 0