vue實(shí)現(xiàn)盒子內(nèi)拖動(dòng)方塊移動(dòng)的示例代碼
vue實(shí)現(xiàn)盒子內(nèi)拖動(dòng)方塊移動(dòng)
本文采用vue2的options api。
1. 創(chuàng)建盒子與方塊
最簡(jiǎn)單的父子嵌套盒子,子盒子絕對(duì)定位。
<template> <div class="Drag"> <div class="scroll_thumb"></div> </div> </template> <script> export default { name: "Drag", }; </script> <style scoped> .Drag { position: relative; width: 1000px; height: 600px; border: 1px solid #333; margin: 100px auto; } .Drag .scroll_thumb { position: absolute; top: 0; left: 0; width: 20px; height: 20px; background-color: gold; } </style>
2.獲取父盒子在文檔的位置信息
使用getBoundingClientRect API獲取
<template> <div ref="drag" class="Drag"> <div class="scroll_thumb"></div> </div> </template> <script> export default { name: "Drag", data() { return { boxRect: {}, //父盒子位置信息 }; }, mounted() { this.setBoxRect(); // 窗口變化時(shí)重新獲取數(shù)據(jù) window.addEventListener("resize", this.setBoxRect); }, beforeDestroy() { window.removeEventListener("resize", this.setBoxRect); }, methods: { setBoxRect() { //獲取父盒子在文檔的位置信息 this.boxRect = this.$refs.drag.getBoundingClientRect(); }, }, } </script>
3.監(jiān)聽(tīng)鼠標(biāo)點(diǎn)擊事件
<template> <div ref="drag" class="Drag"> <div class="scroll_thumb" @mousedown="mousedown"></div> </div> </template> <script> export default { methods: { // 點(diǎn)擊鼠標(biāo)按鍵觸發(fā) mousedown() { // 判斷是否是鼠標(biāo)左鍵 if (event.button !== 0) return; // 監(jiān)聽(tīng)鼠標(biāo)移動(dòng)與彈起事件 document.addEventListener("mousemove", this.mousemove); document.addEventListener("mouseup", this.mouseup); }, // 鼠標(biāo)移動(dòng)觸發(fā) mousemove(event) { // 此為關(guān)鍵代碼,下面進(jìn)行分析 }, // 鼠標(biāo)按鍵彈起時(shí)移除監(jiān)聽(tīng)的時(shí)間 mouseup() { this.removeMouseEvent() }, removeMouseEvent() { document.removeEventListener("mousemove", this.mousemove); document.removeEventListener("mouseup", this.mouseup); }, }, }; </script>
4.計(jì)算方塊跟隨鼠標(biāo)移動(dòng)
<template> <div ref="drag" class="Drag"> <!-- 動(dòng)態(tài)計(jì)算方塊的top與left --> <div class="scroll_thumb" :style="{ width: `${thumbW}px`, height: `${thumbH}px`, top: `${thumbTop}px`, left: `${thumbLeft}px`, }" @mousedown="mousedown" ></div> </div> </template> <script> export default { name: "Drag", data() { return { // 方塊的位置 thumbTop: 0, thumbLeft: 0, // 定義方塊的寬高 thumbW: 20, thumbH: 20, boxRect: {}, }; }, methods: { mousemove(event) { // 阻止瀏覽器默認(rèn)的行為 event.preventDefault(); // 停止冒泡 event.stopPropagation(); // 方塊定位的值 = 鼠標(biāo)位置 - 方塊自身寬高/2 - 父盒子左上角位置的值 // ps1:方塊自身寬高/2,作用是使鼠標(biāo)的位置始終在方塊的中心點(diǎn) // ps2: 父盒子左上角位置的值,是因?yàn)閑vent.clientX/Y是采用文檔定位,而thumbLeft是絕對(duì)定位,所以要矯正偏移的值 this.thumbLeft = event.clientX - this.thumbW / 2 - this.boxRect.left; this.thumbTop = event.clientY - this.thumbH / 2 - this.boxRect.top; }, }, }; </script>
到此已經(jīng)能夠?qū)崿F(xiàn)鼠標(biāo)拖動(dòng)了,但是方塊可以拖動(dòng)到任意位置,下面我們將進(jìn)行限制。
5.將方塊限制在盒子內(nèi)移動(dòng)
<template> <div ref="drag" class="Drag"> <!-- 動(dòng)態(tài)計(jì)算方塊的top與left --> <div class="scroll_thumb" :style="{ width: `${thumbW}px`, height: `${thumbH}px`, top: `${thumbTop}px`, left: `${thumbLeft}px`, }" @mousedown="mousedown" ></div> </div> </template> <script> export default { name: "Drag", data() { return { // 方塊的位置 thumbTop: 0, thumbLeft: 0, // 定義方塊的寬高 thumbW: 20, thumbH: 20, boxRect: {}, }; }, methods: { mousemove(event) { event.preventDefault(); event.stopPropagation(); this.thumbLeft = event.clientX - this.thumbW / 2 - this.boxRect.left; this.thumbTop = event.clientY - this.thumbH / 2 - this.boxRect.top; // 調(diào)用限制 this.setLimit(); }, setLimit() { // 獲取方塊的右側(cè)與底部的值 const thumbRight = this.thumbLeft + this.thumbW; const thumbBottom = this.thumbTop + this.thumbH; // 當(dāng)方塊的位置超過(guò)頂部或左側(cè),將定位的值設(shè)置為0 if (this.thumbLeft <= 0) { this.thumbLeft = 0; } if (this.thumbTop <= 0) { this.thumbTop = 0; } // 當(dāng)方塊的位置超過(guò)底部或者右側(cè),將定位的值設(shè)置為父盒子寬高-方塊本身寬高的值 if (thumbRight >= this.boxRect.width) { this.thumbLeft = this.boxRect.width - this.thumbW; } if (thumbBottom >= this.boxRect.height) { this.thumbTop = this.boxRect.height - this.thumbH; } }, }, }; </script>
6.完整代碼
<template> <div ref="drag" class="Drag"> <!-- 動(dòng)態(tài)計(jì)算方塊的top與left --> <div class="scroll_thumb" :style="{ width: `${thumbW}px`, height: `${thumbH}px`, top: `${thumbTop}px`, left: `${thumbLeft}px`, }" @mousedown="mousedown" ></div> </div> </template> <script> export default { name: "Drag", data() { return { thumbTop: 0, thumbLeft: 0, thumbW: 20, thumbH: 20, boxRect: {}, }; }, mounted() { this.setBoxRect(); window.addEventListener("resize", this.setBoxRect); }, beforeDestroy() { window.removeEventListener("resize", this.setBoxRect); this.removeMouseEvent(); }, methods: { setBoxRect() { this.boxRect = this.$refs.drag.getBoundingClientRect(); }, mousedown(event) { // 判斷是否是鼠標(biāo)左鍵 if (event.button !== 0) return; document.addEventListener("mousemove", this.mousemove); document.addEventListener("mouseup", this.mouseup); }, mousemove(event) { event.preventDefault(); event.stopPropagation(); this.thumbLeft = event.clientX - this.thumbW / 2 - this.boxRect.left; this.thumbTop = event.clientY - this.thumbH / 2 - this.boxRect.top; this.setLimit(); }, setLimit() { const thumbRight = this.thumbLeft + this.thumbW; const thumbBottom = this.thumbTop + this.thumbH; if (this.thumbLeft <= 0) { this.thumbLeft = 0; } if (this.thumbTop <= 0) { this.thumbTop = 0; } if (thumbRight >= this.boxRect.width) { this.thumbLeft = this.boxRect.width - this.thumbW; } if (thumbBottom >= this.boxRect.height) { this.thumbTop = this.boxRect.height - this.thumbH; } }, mouseup() { this.removeMouseEvent(); }, removeMouseEvent() { document.removeEventListener("mousemove", this.mousemove); document.removeEventListener("mouseup", this.mouseup); }, }, }; </script> <style scoped> .Drag { position: relative; width: 1000px; height: 600px; border: 1px solid #333; margin: 100px auto; } .Drag .scroll_thumb { position: absolute; background-color: gold; } </style>
7.效果
8.應(yīng)用
筆者做這個(gè)案例是為了實(shí)現(xiàn)虛擬列表的滾動(dòng)條做的技術(shù)儲(chǔ)備,還有其他應(yīng)用或想法歡迎評(píng)論區(qū)留言。
以上就是vue實(shí)現(xiàn)盒子內(nèi)拖動(dòng)方塊移動(dòng)的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于vue實(shí)現(xiàn)盒子內(nèi)方塊移動(dòng)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Vue代理報(bào)錯(cuò)404問(wèn)題及解決(vue配置proxy)
這篇文章主要介紹了Vue代理報(bào)錯(cuò)404問(wèn)題及解決(vue配置proxy),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12Vue2中pinia刷新后數(shù)據(jù)丟失的問(wèn)題解決
Pinia是一個(gè)Vue.js狀態(tài)管理庫(kù),如果你在組件中修改了store中的數(shù)據(jù)并刷新了界面,Pinia會(huì)將store中的數(shù)據(jù)重置為初始值,從而導(dǎo)致數(shù)據(jù)丟失的問(wèn)題,本文就來(lái)介紹一下問(wèn)題解決,感興趣的可以了解一下2023-12-12Vue3.0利用vue-grid-layout插件實(shí)現(xiàn)拖拽布局
這篇文章主要介紹了Vue3.0利用vue-grid-layout插件實(shí)現(xiàn)拖拽布局,工作中難免遇到需要對(duì)頁(yè)面布局進(jìn)行拖拽然后改變布局,保存布局,下面文章就圍繞Vue3.0利用vue-grid-layout插件實(shí)現(xiàn)拖拽布局的相關(guān)資料展開(kāi)詳細(xì)內(nèi)容,需要的朋友可以參考一下2021-11-11uniapp中設(shè)置全局頁(yè)面背景色的簡(jiǎn)單教程
uni-app如何設(shè)置頁(yè)面全局背景色,其實(shí)非常簡(jiǎn)單,一句話即可,但有時(shí)候也會(huì)踩一些坑,這篇文章主要給大家介紹了關(guān)于uniapp中設(shè)置全局頁(yè)面背景色的相關(guān)資料,需要的朋友可以參考下2023-03-03在vue中實(shí)現(xiàn)echarts隨窗體變化
這篇文章主要介紹了在vue中實(shí)現(xiàn)echarts隨窗體變化,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-07-07vue - vue.config.js中devServer配置方式
今天小編就為大家分享一篇vue - vue.config.js中devServer配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-10-10