vue項(xiàng)目中彈窗拖拽、縮放功能實(shí)現(xiàn)過(guò)程
背景
在項(xiàng)目中有一個(gè)會(huì)話窗口,需要支持用戶拖拽、縮放的功能
實(shí)現(xiàn)
拖拽
指定要拖拽的窗口
// 拖拽 <div ref="resizableBox" ><div class="header"></div></div>
const visible = ref(false)
const position = ref({ x: 200, y: 100 })
const emit = defineEmits(['update:visible', 'closeDialog'])
let dragging = false
let offsetX, offsetY, maxLeft, maxTop
const startDrag = (e) => {
dragging = true
offsetX = e.clientX - position.value.x
offsetY = e.clientY - position.value.y
document.body.style.userSelect = 'none'; // 防止選中文本
document.addEventListener('mousemove', onDrag)
document.addEventListener('mouseup', stopDrag)
}
const onDrag = (e) => {
if (!dragging) return
position.value.x = Math.max(0, Math.min(maxLeft,(e.clientX - offsetX)))
position.value.y = Math.max(0, Math.min(maxTop,(e.clientY - offsetY)))
console.log(maxLeft,position.value.x,maxTop,position.value.y)
}
const stopDrag = () => {
dragging = false
document.removeEventListener('mousemove', onDrag)
document.removeEventListener('mouseup', stopDrag)
}
const initDialogPosition = () => {
// 初始居中:等待 DOM 渲染后計(jì)算中心點(diǎn)
nextTick(() => {
const dialog = document.querySelector('.header')
if (dialog) {
const { innerWidth, innerHeight } = window
const { offsetWidth, offsetHeight } = dialog as HTMLElement
maxLeft = innerWidth - offsetWidth
maxTop = innerHeight - Math.max(560, offsetHeight)
position.value.x = maxLeft / 2
position.value.y = maxTop / 3
console.log('innerWidth', innerWidth, innerHeight)
console.log('dialog', dialog.getBoundingClientRect())
}
})
}
指定拖拽的區(qū)域
const initDialogPosition = () => {
// 初始居中:等待 DOM 渲染后計(jì)算中心點(diǎn)
nextTick(() => {
const dialog = document.querySelector('.header')
if (dialog) {
const { innerWidth, innerHeight } = window
const { offsetWidth, offsetHeight } = dialog as HTMLElement
maxLeft = innerWidth - offsetWidth
maxTop = innerHeight - Math.max(560, offsetHeight)
position.value.x = maxLeft / 2
position.value.y = maxTop / 3
console.log('innerWidth', innerWidth, innerHeight)
console.log('dialog', dialog.getBoundingClientRect())
}
})
}
縮放
指定縮放的對(duì)象
// 縮放 <div ref="resizableBox" ><div class="resizer" @mousedown="initResize"></div></div>
const resizableBox = ref<HTMLElement | null>(null);
function initResize(e: MouseEvent) {
const box = resizableBox.value;
if (!box) return;
const startX = e.clientX;
const startY = e.clientY;
const startWidth = box.offsetWidth;
const startHeight = box.offsetHeight;
function onMouseMove(event: MouseEvent) {
const newWidth = Math.max(400, startWidth + (event.clientX - startX));
const newHeight = Math.max(560, startHeight + (event.clientY - startY));
box.style.width = `${newWidth}px`;
box.style.height = `${newHeight}px`;
}
function onMouseUp() {
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
}
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
}
也可以添加指定區(qū)域,實(shí)現(xiàn)鼠標(biāo)樣式轉(zhuǎn)變
.resizer {
width: 14px;
height: 14px;
position: absolute;
right: 0;
bottom: 0;
cursor: se-resize;
z-index: 10;
border-radius: 2px;
}
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
從Vue到Postman全面驗(yàn)證API接口跨域問(wèn)題解決
我們都知道跨域是同源策略導(dǎo)致的,域名不同、協(xié)議不同、端口號(hào)不同任意一種情況都會(huì)導(dǎo)致跨域,這篇文章主要介紹了從Vue到Postman全面驗(yàn)證API接口跨域問(wèn)題,需要的朋友可以參考下2024-08-08
Vue的事件響應(yīng)式進(jìn)度條組件實(shí)例詳解
這篇文章主要介紹了Vue的事件響應(yīng)式進(jìn)度條組件的實(shí)例代碼,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2018-02-02
Vue Element前端應(yīng)用開發(fā)之echarts圖表
在我們做應(yīng)用系統(tǒng)的時(shí)候,往往都會(huì)涉及圖表的展示,綜合的圖表展示能夠給客戶帶來(lái)視覺(jué)的享受和數(shù)據(jù)直觀體驗(yàn),同時(shí)也是增強(qiáng)客戶認(rèn)同感的舉措之一2021-05-05
使用vue自定義如何實(shí)現(xiàn)Tree組件和拖拽功能
這篇文章主要介紹了使用vue自定義如何實(shí)現(xiàn)Tree組件和拖拽功能,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12
Vue3數(shù)字滾動(dòng)插件vue-countup-v3的使用
vue-countup-v3 插件是一個(gè)基于 Vue3 的數(shù)字動(dòng)畫插件,用于在網(wǎng)站或應(yīng)用程序中創(chuàng)建帶有數(shù)字動(dòng)畫效果的計(jì)數(shù)器,本文主要介紹了Vue3數(shù)字滾動(dòng)插件vue-countup-v3的使用,感興趣的可以了解一下2023-10-10
關(guān)于element-ui resetFields重置方法無(wú)效問(wèn)題及解決
這篇文章主要介紹了關(guān)于element-ui resetFields重置方法無(wú)效問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08
electron-vite工具打包后如何通過(guò)內(nèi)置配置文件動(dòng)態(tài)修改接口地址
使用electron-vite?工具開發(fā)項(xiàng)目打包完后每次要改接口地址都要重新打包,對(duì)于多環(huán)境切換或者頻繁變更接口地址就顯得麻煩,這篇文章主要介紹了electron-vite工具打包后通過(guò)內(nèi)置配置文件動(dòng)態(tài)修改接口地址實(shí)現(xiàn)方法,需要的朋友可以參考下2024-05-05
Vue項(xiàng)目通過(guò)network的ip地址訪問(wèn)注意事項(xiàng)及說(shuō)明
這篇文章主要介紹了Vue項(xiàng)目通過(guò)network的ip地址訪問(wèn)注意事項(xiàng)及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09

