感謝參考原文-http://bjbsair.com/2020-03-27/tech-info/7202.html
前言
在本文中將會(huì)用Vue完成九宮格拖拽效果讶迁,同時(shí)介紹一下網(wǎng)格布局佛寿。具體代碼以及demo可以點(diǎn)以下超鏈接進(jìn)入
效果實(shí)例
Demo
簡(jiǎn)單了解Grid布局(網(wǎng)格布局)
什么是網(wǎng)格布局
CSS網(wǎng)格布局(又稱(chēng)“網(wǎng)格”),是一種二維網(wǎng)格布局系統(tǒng)效斑。CSS在處理網(wǎng)頁(yè)布局方面一直做的不是很好。一開(kāi)始我們用的是table(表格)布局,然后用float(浮動(dòng))擦秽,position(定位)和inline-block(行內(nèi)塊)布局合呐,但是這些方法本質(zhì)上是hack暮的,遺漏了很多功能,例如垂直居中淌实。后來(lái)出了flexbox(盒子布局)冻辩,解決了很多布局問(wèn)題猖腕,但是它僅僅是一維布局,而不是復(fù)雜的二維布局恨闪,實(shí)際上它們(flexbox與grid)能很好的配合使用倘感。Grid布局是第一個(gè)專(zhuān)門(mén)為解決布局問(wèn)題而創(chuàng)建的CSS模塊.
grid
簡(jiǎn)單說(shuō)說(shuō)網(wǎng)格布局的屬性
- display: grid: 生成塊級(jí)網(wǎng)格 inline-grid: 生成行內(nèi)網(wǎng)格 subgrid: 如果網(wǎng)格容器本身是網(wǎng)格項(xiàng)(嵌套網(wǎng)格容器),此屬性用來(lái)繼承其父網(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 縮寫(xiě)形式 grid-gap: <grid-row-gap> <grid-column-gap>
- justify-items 水平方向?qū)R方式(在這里只是簡(jiǎn)單說(shuō)明) start: 左對(duì)齊 end: 右對(duì)齊 center: 居中對(duì)齊 stretch: 填滿(mǎn)(默認(rèn))
- align-items 垂直方向?qū)R方式 start: 頂部對(duì)齊 end: 底部對(duì)齊 center: 居中對(duì)齊 stretch:填滿(mǎn)(默認(rèn))
當(dāng)然,如果看不懂也不要緊钧敞,這里有一篇個(gè)人十分喜歡的網(wǎng)格布局的文章蜡豹。里面介紹得十分詳細(xì)「瓤粒可以供大家深入學(xué)習(xí)網(wǎng)格布局內(nèi)容镜廉。
傳送門(mén):Grid布局指南
http://www.reibang.com/p/d183265a8dad
實(shí)現(xiàn)九宮格布局
/*css*/
.container{
position: relative; /*實(shí)現(xiàn)定位,使得滑塊定位相對(duì)于此*/
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" /*定義個(gè)格子的名稱(chēng)娇唯,方便計(jì)算*/
"main1 main2 main3"
"footer1 footer2 footer3";
border: 1px solid #000;
margin: 0 auto;
}
.block{
position: absolute; /*相對(duì)于container定位*/
width: 100px;
height: 100px;
display: flex; /*flex布局,使得文字在中央*/
justify-content: center;
justify-items: center;
align-items: center;
align-content: center;
user-select: none; /*用戶(hù)不可選定文字*/
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代碼部分
在這里我選取一些核心代碼出來(lái)講解凤巨。代碼有所省略视乐,因?yàn)榇a著實(shí)有點(diǎn)長(zhǎng),太占篇幅而且沒(méi)多大意義敢茁,如果需要瀏覽全部代碼可以點(diǎn)擊上面的Demo連接佑淀。
<script>
//引入animate.css 沒(méi)有手撕css動(dòng)畫(huà),直接用了animate.css實(shí)現(xiàn)我們的動(dòng)畫(huà)效果
import animate from 'animate.css';
export default {
name: 'app',
data () {
return {
positionX:0, //定義方塊的兩個(gè)坐標(biāo)
positionY:0,
}
},
methods:{
move(e){
let oDiv = e.target; //獲取點(diǎn)擊的目標(biāo)元素
let gDiv = e.path[1]; //獲取點(diǎn)擊元素的父級(jí)元素
/*獲取點(diǎn)擊時(shí)的偏移位置彰檬,在這里要注意一下
**由于我們用的是網(wǎng)格布局,每在一個(gè)格子中相對(duì)位置都是相對(duì)格子來(lái)算的伸刃,不是相對(duì)于父級(jí)盒子左上角
**也就是說(shuō)當(dāng)你把方塊移動(dòng)到九個(gè)格子中任意一個(gè)時(shí),方塊的位置都是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)拖動(dòng)時(shí)捧颅,算出的值就剛好是方塊的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的移動(dòng)范圍
case "head2 / head2 / head2 / head2":this.rangeOfHead2(left,top,oDiv);break; //實(shí)現(xiàn)head2的移動(dòng)范圍
case "head3 / head3 / head3 / head3":this.rangeOfHead3(left,top,oDiv);break; //實(shí)現(xiàn)head3的移動(dòng)范圍
case "main1 / main1 / main1 / main1":this.rangeOfMain1(left,top,oDiv);break; //實(shí)現(xiàn)main1的移動(dòng)范圍
...
}
};
document.onmouseup = (e)=>{
//當(dāng)鼠標(biāo)抬起時(shí),我們要做的事
//通過(guò)點(diǎn)擊位置和父級(jí)元素的偏移判斷方塊在哪個(gè)區(qū)域
if(e.clientY-gDiv.offsetTop<100&&e.clientX-gDiv.offsetLeft<100){
//將方塊移動(dòng)到該區(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)聽(tīng)取消
document.onmousedown = null; //需要把事件監(jiān)聽(tīng)取消
//當(dāng)然较雕,不能忘記我們的動(dòng)畫(huà)hhh
oDiv.className = "block animated wobble";
let removeClass = setTimeout(()=>{
oDiv.className = "block animated";
},500);
};
},
rangeOfHead1(x,y,oDiv){ //判斷head1格子中的可以移動(dòng)范圍
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格子中的可以移動(dòng)范圍
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){ //將方塊移入到對(duì)應(yīng)的區(qū)域中
this.positionX = 0;
this.positionY = 0;
oDiv.style.gridArea=blockName;
}
},
}
</script>
總結(jié)
到這里我們把九宮格拖拽實(shí)現(xiàn)了碉哑,同時(shí)學(xué)習(xí)了Grid(網(wǎng)格布局)×两總的做下來(lái)扣典,發(fā)現(xiàn)用網(wǎng)格布局做網(wǎng)格拖拽更加費(fèi)事,但是為了后續(xù)可以方便一些慎玖,也只好搗鼓下來(lái)了贮尖。到這里我們就把基于Vue的九宮格拖拽實(shí)現(xiàn)了,有問(wèn)題或者發(fā)現(xiàn)錯(cuò)誤的請(qǐng)指正趁怔,謝謝大家
珍惜淡定的心境湿硝,苦過(guò)后更加清感謝參考原文-http://bjbsair.com/2020-03-27/tech-info/7202/
前言
在本文中將會(huì)用Vue完成九宮格拖拽效果薪前,同時(shí)介紹一下網(wǎng)格布局。具體代碼以及demo可以點(diǎn)以下超鏈接進(jìn)入
效果實(shí)例
Demo
簡(jiǎn)單了解Grid布局(網(wǎng)格布局)
什么是網(wǎng)格布局
CSS網(wǎng)格布局(又稱(chēng)“網(wǎng)格”)关斜,是一種二維網(wǎng)格布局系統(tǒng)示括。CSS在處理網(wǎng)頁(yè)布局方面一直做的不是很好。一開(kāi)始我們用的是table(表格)布局蚤吹,然后用float(浮動(dòng))例诀,position(定位)和inline-block(行內(nèi)塊)布局,但是這些方法本質(zhì)上是hack裁着,遺漏了很多功能,例如垂直居中拱她。后來(lái)出了flexbox(盒子布局)二驰,解決了很多布局問(wèn)題,但是它僅僅是一維布局秉沼,而不是復(fù)雜的二維布局桶雀,實(shí)際上它們(flexbox與grid)能很好的配合使用。Grid布局是第一個(gè)專(zhuān)門(mén)為解決布局問(wèn)題而創(chuàng)建的CSS模塊.
grid
簡(jiǎn)單說(shuō)說(shuō)網(wǎng)格布局的屬性
- display: grid: 生成塊級(jí)網(wǎng)格 inline-grid: 生成行內(nèi)網(wǎng)格 subgrid: 如果網(wǎng)格容器本身是網(wǎng)格項(xiàng)(嵌套網(wǎng)格容器)唬复,此屬性用來(lái)繼承其父網(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 縮寫(xiě)形式 grid-gap: <grid-row-gap> <grid-column-gap>
- justify-items 水平方向?qū)R方式(在這里只是簡(jiǎn)單說(shuō)明) start: 左對(duì)齊 end: 右對(duì)齊 center: 居中對(duì)齊 stretch: 填滿(mǎn)(默認(rèn))
- align-items 垂直方向?qū)R方式 start: 頂部對(duì)齊 end: 底部對(duì)齊 center: 居中對(duì)齊 stretch:填滿(mǎn)(默認(rèn))
當(dāng)然敞咧,如果看不懂也不要緊棘捣,這里有一篇個(gè)人十分喜歡的網(wǎng)格布局的文章。里面介紹得十分詳細(xì)休建≌Э郑可以供大家深入學(xué)習(xí)網(wǎng)格布局內(nèi)容。
傳送門(mén):Grid布局指南
http://www.reibang.com/p/d183265a8dad
實(shí)現(xiàn)九宮格布局
/*css*/
.container{
position: relative; /*實(shí)現(xiàn)定位测砂,使得滑塊定位相對(duì)于此*/
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" /*定義個(gè)格子的名稱(chēng),方便計(jì)算*/
"main1 main2 main3"
"footer1 footer2 footer3";
border: 1px solid #000;
margin: 0 auto;
}
.block{
position: absolute; /*相對(duì)于container定位*/
width: 100px;
height: 100px;
display: flex; /*flex布局砌些,使得文字在中央*/
justify-content: center;
justify-items: center;
align-items: center;
align-content: center;
user-select: none; /*用戶(hù)不可選定文字*/
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代碼部分
在這里我選取一些核心代碼出來(lái)講解呜投。代碼有所省略,因?yàn)榇a著實(shí)有點(diǎn)長(zhǎng)存璃,太占篇幅而且沒(méi)多大意義仑荐,如果需要瀏覽全部代碼可以點(diǎn)擊上面的Demo連接。
<script>
//引入animate.css 沒(méi)有手撕css動(dòng)畫(huà)有巧,直接用了animate.css實(shí)現(xiàn)我們的動(dòng)畫(huà)效果
import animate from 'animate.css';
export default {
name: 'app',
data () {
return {
positionX:0, //定義方塊的兩個(gè)坐標(biāo)
positionY:0,
}
},
methods:{
move(e){
let oDiv = e.target; //獲取點(diǎn)擊的目標(biāo)元素
let gDiv = e.path[1]; //獲取點(diǎn)擊元素的父級(jí)元素
/*獲取點(diǎn)擊時(shí)的偏移位置释漆,在這里要注意一下
**由于我們用的是網(wǎng)格布局,每在一個(gè)格子中相對(duì)位置都是相對(duì)格子來(lái)算的,不是相對(duì)于父級(jí)盒子左上角
**也就是說(shuō)當(dāng)你把方塊移動(dòng)到九個(gè)格子中任意一個(gè)時(shí)篮迎,方塊的位置都是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)拖動(dòng)時(shí)示姿,算出的值就剛好是方塊的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的移動(dòng)范圍
case "head2 / head2 / head2 / head2":this.rangeOfHead2(left,top,oDiv);break; //實(shí)現(xiàn)head2的移動(dòng)范圍
case "head3 / head3 / head3 / head3":this.rangeOfHead3(left,top,oDiv);break; //實(shí)現(xiàn)head3的移動(dòng)范圍
case "main1 / main1 / main1 / main1":this.rangeOfMain1(left,top,oDiv);break; //實(shí)現(xiàn)main1的移動(dòng)范圍
...
}
};
document.onmouseup = (e)=>{
//當(dāng)鼠標(biāo)抬起時(shí),我們要做的事
//通過(guò)點(diǎn)擊位置和父級(jí)元素的偏移判斷方塊在哪個(gè)區(qū)域
if(e.clientY-gDiv.offsetTop<100&&e.clientX-gDiv.offsetLeft<100){
//將方塊移動(dòng)到該區(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)聽(tīng)取消
document.onmousedown = null; //需要把事件監(jiān)聽(tīng)取消
//當(dāng)然逊笆,不能忘記我們的動(dòng)畫(huà)hhh
oDiv.className = "block animated wobble";
let removeClass = setTimeout(()=>{
oDiv.className = "block animated";
},500);
};
},
rangeOfHead1(x,y,oDiv){ //判斷head1格子中的可以移動(dòng)范圍
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格子中的可以移動(dòng)范圍
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){ //將方塊移入到對(duì)應(yīng)的區(qū)域中
this.positionX = 0;
this.positionY = 0;
oDiv.style.gridArea=blockName;
}
},
}
</script>
總結(jié)
到這里我們把九宮格拖拽實(shí)現(xiàn)了栈戳,同時(shí)學(xué)習(xí)了Grid(網(wǎng)格布局)∧疡桑總的做下來(lái)子檀,發(fā)現(xiàn)用網(wǎng)格布局做網(wǎng)格拖拽更加費(fèi)事,但是為了后續(xù)可以方便一些乃戈,也只好搗鼓下來(lái)了褂痰。到這里我們就把基于Vue的九宮格拖拽實(shí)現(xiàn)了,有問(wèn)題或者發(fā)現(xiàn)錯(cuò)誤的請(qǐng)指正症虑,謝謝大家
珍惜淡定的心境缩歪,苦過(guò)后更加清