Vue實(shí)現(xiàn)拖拽升級(九宮格拖拽)

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

基于Vue實(shí)現(xiàn)拖拽升級(九宮格拖拽)

前言

在本文中將會用Vue完成九宮格拖拽效果,同時介紹一下網(wǎng)格布局。具體代碼以及demo可以點(diǎn)以下超鏈接進(jìn)入

效果實(shí)例

基于Vue實(shí)現(xiàn)拖拽升級(九宮格拖拽)

Demo

簡單了解Grid布局(網(wǎng)格布局)

什么是網(wǎng)格布局

CSS網(wǎng)格布局(又稱“網(wǎng)格”),是一種二維網(wǎng)格布局系統(tǒng)。CSS在處理網(wǎng)頁布局方面一直做的不是很好。一開始我們用的是table(表格)布局,然后用float(浮動),position(定位)和inline-block(行內(nèi)塊)布局,但是這些方法本質(zhì)上是hack,遺漏了很多功能,例如垂直居中。后來出了flexbox(盒子布局),解決了很多布局問題,但是它僅僅是一維布局,而不是復(fù)雜的二維布局,實(shí)際上它們(flexbox與grid)能很好的配合使用。Grid布局是第一個專門為解決布局問題而創(chuàng)建的CSS模塊.

基于Vue實(shí)現(xiàn)拖拽升級(九宮格拖拽)

grid

簡單說說網(wǎng)格布局的屬性

  • display: grid: 生成塊級網(wǎng)格 inline-grid: 生成行內(nèi)網(wǎng)格 subgrid: 如果網(wǎng)格容器本身是網(wǎng)格項(xiàng)(嵌套網(wǎng)格容器),此屬性用來繼承其父網(wǎng)格容器的列、行大小。
  • grid-template-columns 設(shè)置網(wǎng)格列大小
  • grid-template-rows 設(shè)置網(wǎng)格行大小
  • grid-template-areas 設(shè)置網(wǎng)格區(qū)域
  • grid-column-gap 設(shè)置網(wǎng)格列間距
  • grid-row-gap 設(shè)置網(wǎng)格行間距
  • grid-gap 縮寫形式 grid-gap: <grid-row-gap> <grid-column-gap>
  • justify-items 水平方向?qū)R方式(在這里只是簡單說明) start: 左對齊 end: 右對齊 center: 居中對齊 stretch: 填滿(默認(rèn))
  • align-items 垂直方向?qū)R方式 start: 頂部對齊 end: 底部對齊 center: 居中對齊 stretch:填滿(默認(rèn))

當(dāng)然,如果看不懂也不要緊,這里有一篇個人十分喜歡的網(wǎng)格布局的文章。里面介紹得十分詳細(xì)??梢怨┐蠹疑钊雽W(xué)習(xí)網(wǎng)格布局內(nèi)容。

傳送門:Grid布局指南

http://www.itdecent.cn/p/d183265a8dad

實(shí)現(xiàn)九宮格布局

/*css*/  
  
  .container{  
    position: relative;   /*實(shí)現(xiàn)定位,使得滑塊定位相對于此*/  
    display: grid;        /*定義網(wǎng)格布局*/  
    width: 300px;  
    height: 300px;  
    grid-template-columns: 100px 100px 100px;     /*實(shí)現(xiàn)九宮格,行列各三*/  
    grid-template-rows: 100px 100px 100px;  
    grid-template-areas: "head1 head2 head3"      /*定義個格子的名稱,方便計(jì)算*/  
                          "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>  

實(shí)現(xiàn)拖拽的JS代碼部分

在這里我選取一些核心代碼出來講解。代碼有所省略,因?yàn)榇a著實(shí)有點(diǎn)長,太占篇幅而且沒多大意義,如果需要瀏覽全部代碼可以點(diǎn)擊上面的Demo連接。

<script>  
//引入animate.css 沒有手撕css動畫,直接用了animate.css實(shí)現(xiàn)我們的動畫效果  
import animate from 'animate.css';  
  
export default {  
  name: 'app',  
  data () {  
    return {  
      positionX:0,      //定義方塊的兩個坐標(biāo)  
      positionY:0,  
    }  
  },  
  methods:{  
    move(e){  
      let oDiv = e.target;      //獲取點(diǎn)擊的目標(biāo)元素  
      let gDiv = e.path[1];     //獲取點(diǎn)擊元素的父級元素  
        
      /*獲取點(diǎn)擊時的偏移位置,在這里要注意一下  
      **由于我們用的是網(wǎng)格布局,每在一個格子中相對位置都是相對格子來算的,不是相對于父級盒子左上角  
      **也就是說當(dāng)你把方塊移動到九個格子中任意一個時,方塊的位置都是top:0和left:0  
      */  
        
      //所以這里我們直接取鼠標(biāo)點(diǎn)擊的位置減去點(diǎn)擊盒子的偏移位置,也就是0  
      let disX = e.clientX - 0;       
      let disY = e.clientY - 0;  
      document.onmousemove = (e)=>{  
        
        //當(dāng)拖動時,算出的值就剛好是方塊的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;    //實(shí)現(xiàn)head1的移動范圍  
          case "head2 / head2 / head2 / head2":this.rangeOfHead2(left,top,oDiv);break;    //實(shí)現(xiàn)head2的移動范圍  
          case "head3 / head3 / head3 / head3":this.rangeOfHead3(left,top,oDiv);break;    //實(shí)現(xiàn)head3的移動范圍  
          case "main1 / main1 / main1 / main1":this.rangeOfMain1(left,top,oDiv);break;    //實(shí)現(xiàn)main1的移動范圍  
          ...  
        }  
      };  
      document.onmouseup = (e)=>{  
        //當(dāng)鼠標(biāo)抬起時,我們要做的事  
        //通過點(diǎn)擊位置和父級元素的偏移判斷方塊在哪個區(qū)域  
        if(e.clientY-gDiv.offsetTop<100&&e.clientX-gDiv.offsetLeft<100){  
          
          //將方塊移動到該區(qū)域中  
          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;      //需要把事件監(jiān)聽取消  
        document.onmousedown = null;    //需要把事件監(jiān)聽取消  
          
        //當(dāng)然,不能忘記我們的動畫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){    //將方塊移入到對應(yīng)的區(qū)域中  
      this.positionX = 0;  
      this.positionY = 0;  
      oDiv.style.gridArea=blockName;  
    }  
  },  
}  
</script>  

總結(jié)

到這里我們把九宮格拖拽實(shí)現(xiàn)了,同時學(xué)習(xí)了Grid(網(wǎng)格布局)。總的做下來,發(fā)現(xiàn)用網(wǎng)格布局做網(wǎng)格拖拽更加費(fèi)事,但是為了后續(xù)可以方便一些,也只好搗鼓下來了。到這里我們就把基于Vue的九宮格拖拽實(shí)現(xiàn)了,有問題或者發(fā)現(xiàn)錯誤的請指正,謝謝大家

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

基于Vue實(shí)現(xiàn)拖拽升級(九宮格拖拽)

前言

在本文中將會用Vue完成九宮格拖拽效果,同時介紹一下網(wǎng)格布局。具體代碼以及demo可以點(diǎn)以下超鏈接進(jìn)入

效果實(shí)例

基于Vue實(shí)現(xiàn)拖拽升級(九宮格拖拽)

Demo

簡單了解Grid布局(網(wǎng)格布局)

什么是網(wǎng)格布局

CSS網(wǎng)格布局(又稱“網(wǎng)格”),是一種二維網(wǎng)格布局系統(tǒng)。CSS在處理網(wǎng)頁布局方面一直做的不是很好。一開始我們用的是table(表格)布局,然后用float(浮動),position(定位)和inline-block(行內(nèi)塊)布局,但是這些方法本質(zhì)上是hack,遺漏了很多功能,例如垂直居中。后來出了flexbox(盒子布局),解決了很多布局問題,但是它僅僅是一維布局,而不是復(fù)雜的二維布局,實(shí)際上它們(flexbox與grid)能很好的配合使用。Grid布局是第一個專門為解決布局問題而創(chuàng)建的CSS模塊.

基于Vue實(shí)現(xiàn)拖拽升級(九宮格拖拽)

grid

簡單說說網(wǎng)格布局的屬性

  • display: grid: 生成塊級網(wǎng)格 inline-grid: 生成行內(nèi)網(wǎng)格 subgrid: 如果網(wǎng)格容器本身是網(wǎng)格項(xiàng)(嵌套網(wǎng)格容器),此屬性用來繼承其父網(wǎng)格容器的列、行大小。
  • grid-template-columns 設(shè)置網(wǎng)格列大小
  • grid-template-rows 設(shè)置網(wǎng)格行大小
  • grid-template-areas 設(shè)置網(wǎng)格區(qū)域
  • grid-column-gap 設(shè)置網(wǎng)格列間距
  • grid-row-gap 設(shè)置網(wǎng)格行間距
  • grid-gap 縮寫形式 grid-gap: <grid-row-gap> <grid-column-gap>
  • justify-items 水平方向?qū)R方式(在這里只是簡單說明) start: 左對齊 end: 右對齊 center: 居中對齊 stretch: 填滿(默認(rèn))
  • align-items 垂直方向?qū)R方式 start: 頂部對齊 end: 底部對齊 center: 居中對齊 stretch:填滿(默認(rèn))

當(dāng)然,如果看不懂也不要緊,這里有一篇個人十分喜歡的網(wǎng)格布局的文章。里面介紹得十分詳細(xì)??梢怨┐蠹疑钊雽W(xué)習(xí)網(wǎng)格布局內(nèi)容。

傳送門:Grid布局指南

http://www.itdecent.cn/p/d183265a8dad

實(shí)現(xiàn)九宮格布局

/*css*/  
  
  .container{  
    position: relative;   /*實(shí)現(xiàn)定位,使得滑塊定位相對于此*/  
    display: grid;        /*定義網(wǎng)格布局*/  
    width: 300px;  
    height: 300px;  
    grid-template-columns: 100px 100px 100px;     /*實(shí)現(xiàn)九宮格,行列各三*/  
    grid-template-rows: 100px 100px 100px;  
    grid-template-areas: "head1 head2 head3"      /*定義個格子的名稱,方便計(jì)算*/  
                          "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>  

實(shí)現(xiàn)拖拽的JS代碼部分

在這里我選取一些核心代碼出來講解。代碼有所省略,因?yàn)榇a著實(shí)有點(diǎn)長,太占篇幅而且沒多大意義,如果需要瀏覽全部代碼可以點(diǎn)擊上面的Demo連接。

<script>  
//引入animate.css 沒有手撕css動畫,直接用了animate.css實(shí)現(xiàn)我們的動畫效果  
import animate from 'animate.css';  
  
export default {  
  name: 'app',  
  data () {  
    return {  
      positionX:0,      //定義方塊的兩個坐標(biāo)  
      positionY:0,  
    }  
  },  
  methods:{  
    move(e){  
      let oDiv = e.target;      //獲取點(diǎn)擊的目標(biāo)元素  
      let gDiv = e.path[1];     //獲取點(diǎn)擊元素的父級元素  
        
      /*獲取點(diǎn)擊時的偏移位置,在這里要注意一下  
      **由于我們用的是網(wǎng)格布局,每在一個格子中相對位置都是相對格子來算的,不是相對于父級盒子左上角  
      **也就是說當(dāng)你把方塊移動到九個格子中任意一個時,方塊的位置都是top:0和left:0  
      */  
        
      //所以這里我們直接取鼠標(biāo)點(diǎn)擊的位置減去點(diǎn)擊盒子的偏移位置,也就是0  
      let disX = e.clientX - 0;       
      let disY = e.clientY - 0;  
      document.onmousemove = (e)=>{  
        
        //當(dāng)拖動時,算出的值就剛好是方塊的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;    //實(shí)現(xiàn)head1的移動范圍  
          case "head2 / head2 / head2 / head2":this.rangeOfHead2(left,top,oDiv);break;    //實(shí)現(xiàn)head2的移動范圍  
          case "head3 / head3 / head3 / head3":this.rangeOfHead3(left,top,oDiv);break;    //實(shí)現(xiàn)head3的移動范圍  
          case "main1 / main1 / main1 / main1":this.rangeOfMain1(left,top,oDiv);break;    //實(shí)現(xiàn)main1的移動范圍  
          ...  
        }  
      };  
      document.onmouseup = (e)=>{  
        //當(dāng)鼠標(biāo)抬起時,我們要做的事  
        //通過點(diǎn)擊位置和父級元素的偏移判斷方塊在哪個區(qū)域  
        if(e.clientY-gDiv.offsetTop<100&&e.clientX-gDiv.offsetLeft<100){  
          
          //將方塊移動到該區(qū)域中  
          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;      //需要把事件監(jiān)聽取消  
        document.onmousedown = null;    //需要把事件監(jiān)聽取消  
          
        //當(dāng)然,不能忘記我們的動畫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){    //將方塊移入到對應(yīng)的區(qū)域中  
      this.positionX = 0;  
      this.positionY = 0;  
      oDiv.style.gridArea=blockName;  
    }  
  },  
}  
</script>  

總結(jié)

到這里我們把九宮格拖拽實(shí)現(xiàn)了,同時學(xué)習(xí)了Grid(網(wǎng)格布局)??偟淖鱿聛?,發(fā)現(xiàn)用網(wǎng)格布局做網(wǎng)格拖拽更加費(fèi)事,但是為了后續(xù)可以方便一些,也只好搗鼓下來了。到這里我們就把基于Vue的九宮格拖拽實(shí)現(xiàn)了,有問題或者發(fā)現(xiàn)錯誤的請指正,謝謝大家

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 前言 在本文中將會用Vue完成九宮格拖拽效果,同時介紹一下網(wǎng)格布局。具體代碼以及demo可以點(diǎn)以下超鏈接進(jìn)入 傳送...
    bb7bb閱讀 7,393評論 5 25
  • 效果實(shí)例 簡單了解Grid布局(網(wǎng)格布局) 什么是網(wǎng)格布局 CSS網(wǎng)格布局(又稱“網(wǎng)格”),是一種二維網(wǎng)格布局系統(tǒng)...
    他方l閱讀 309評論 0 0
  • 效果實(shí)例 簡單了解Grid布局(網(wǎng)格布局) 什么是網(wǎng)格布局 CSS網(wǎng)格布局(又稱“網(wǎng)格”),是一種二維網(wǎng)格布局系統(tǒng)...
    HeroXin閱讀 369評論 0 1
  • 簡介CSS網(wǎng)格布局(又稱“網(wǎng)格”),是一種二維網(wǎng)格布局系統(tǒng)。CSS在處理網(wǎng)頁布局方面一直做的不是很好。一開始我們用...
    _leonlee閱讀 65,765評論 25 173
  • 簡介 CSS網(wǎng)格布局(又名“網(wǎng)格”)是一個二維的基于網(wǎng)格的布局系統(tǒng),其目的只在于完全改變我們設(shè)計(jì)基于網(wǎng)格的用戶界面...
    禮知白閱讀 726評論 0 0

友情鏈接更多精彩內(nèi)容