Skip to content

Commit

Permalink
fix: fix the layer bug : can't move
Browse files Browse the repository at this point in the history
  • Loading branch information
cmdparkour committed Mar 13, 2022
1 parent 0a009e4 commit 956bc42
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 140 deletions.
5 changes: 5 additions & 0 deletions src/components/cropper/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,9 @@
align-items: center;
width: 49%;
}
.upload-demo {
display: flex;
align-items: center;
}
</style>
79 changes: 37 additions & 42 deletions src/components/cropper/tip.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,59 +2,54 @@
<div class="tip-box" v-for="(array1, index1) in handleData" :key="index1">
<el-button-group v-for="(array2, index2) in array1" :key="index2">
<el-tooltip v-for="(row, index3) in array2" :key="index3" :content="row.tip" :show-after="1000" :class="row.class" effect="dark" placement="top">
<el-button type="primary" :icon="row.icon" size="mini" @click="row.command"></el-button>
<el-button type="primary" :icon="row.icon" size="small" @click="row.command"></el-button>
</el-tooltip>
</el-button-group>
</div>
</template>

<script lang="ts">
<script lang="ts" setup>
import type { PropType } from 'vue'
import { defineComponent } from 'vue'
import type Cropper from 'cropperjs'
import { Rank, Crop, Refresh, Back, Right, Top, Bottom, ZoomIn, ZoomOut, RefreshLeft, RefreshRight, Sort } from '@element-plus/icons'
export default defineComponent({
props: {
cropper: {
type: Object as PropType<Cropper>,
required: true
}
},
setup(props) {
const handleData = [
[
[
{ icon: Rank, tip: '切换模式:图片移动', command: () => props.cropper.setDragMode('move') },
{ icon: Crop, tip: '切换模式:裁剪功能', command: () => props.cropper.setDragMode('crop') },
{ icon: Refresh, tip: '重置裁剪框', command: () => props.cropper.reset() }
],
[
{ icon: Back, tip: '图片左移', command: () => props.cropper.move(-10, 0) },
{ icon: Right, tip: '图片右移', command: () => props.cropper.move(10, 0) },
{ icon: Top, tip: '图片上移', command: () => props.cropper.move(0, -10) },
{ icon: Bottom, tip: '图片下移', command: () => props.cropper.move(0, 10) }
]
],
[
[
{ icon: ZoomIn, tip: '图片放大', command: () => props.cropper.zoom(0.1) },
{ icon: ZoomOut, tip: '图片缩小', command: () => props.cropper.zoom(-0.1) },
],
[
{ icon: RefreshLeft, tip: '向左旋转45度', command: () => props.cropper.rotate(-45) },
{ icon: RefreshRight, tip: '向右旋转45度', command: () => props.cropper.rotate(45) },
],
[
{ icon: Sort, tip: '垂直翻转', command: () => props.cropper.scaleY(props.cropper.getImageData().scaleY === 1 ? -1 : 1 ) },
{ icon: Sort, tip: '水平翻转', command: () => props.cropper.scaleX(props.cropper.getImageData().scaleX === 1 ? -1 : 1 ), class: "reverse" },
]
]
]
return {
handleData
}
const props = defineProps({
cropper: {
type: Object as PropType<Cropper>,
required: true
}
})
const handleData = [
[
[
{ icon: Rank, tip: '切换模式:图片移动', command: () => props.cropper.setDragMode('move') },
{ icon: Crop, tip: '切换模式:裁剪功能', command: () => props.cropper.setDragMode('crop') },
{ icon: Refresh, tip: '重置裁剪框', command: () => props.cropper.reset() }
],
[
{ icon: Back, tip: '图片左移', command: () => props.cropper.move(-10, 0) },
{ icon: Right, tip: '图片右移', command: () => props.cropper.move(10, 0) },
{ icon: Top, tip: '图片上移', command: () => props.cropper.move(0, -10) },
{ icon: Bottom, tip: '图片下移', command: () => props.cropper.move(0, 10) }
]
],
[
[
{ icon: ZoomIn, tip: '图片放大', command: () => props.cropper.zoom(0.1) },
{ icon: ZoomOut, tip: '图片缩小', command: () => props.cropper.zoom(-0.1) },
],
[
{ icon: RefreshLeft, tip: '向左旋转45度', command: () => props.cropper.rotate(-45) },
{ icon: RefreshRight, tip: '向右旋转45度', command: () => props.cropper.rotate(45) },
],
[
{ icon: Sort, tip: '垂直翻转', command: () => props.cropper.scaleY(props.cropper.getImageData().scaleY === 1 ? -1 : 1 ) },
{ icon: Sort, tip: '水平翻转', command: () => props.cropper.scaleX(props.cropper.getImageData().scaleX === 1 ? -1 : 1 ), class: "reverse" },
]
]
]
</script>

<style lang="scss" scoped>
Expand Down
2 changes: 1 addition & 1 deletion src/components/layer/index.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div v-drag>
<div v-drag="layer.show">
<el-dialog
ref="dialog"
v-model="layer.show"
Expand Down
224 changes: 127 additions & 97 deletions src/directive/drag/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,112 +9,142 @@ interface ElType extends HTMLDivElement {
__mouseMove__: any,
__sizeChange__: any
}
interface DataDialog {
x: number
y: number
width: number
height: number
marginTop?: string|number
top?: number
bottom?: number
left?: number
right?: number
}
const drag: Directive = {
mounted(el: ElType) {
const dialog = el.querySelector('.el-dialog') as HTMLElement
console.log(dialog)
const header = el.querySelector('.el-dialog__header') as HTMLElement
const dialogMask = el.querySelector('.el-overlay') as HTMLElement
dialogMask.style.cssText += "overflow: hidden;"
header.style.cursor = 'move'
let dragStatus = false
let data = { // 数据源,不变部分为:window信息、dialog信息、mouse初始值信息,可变部分为:拖拽坐标位移
window: { // window信息
width: 0,
height: 0,
},
dialog: {
x: 0,
y: 0,
width: 0,
height: 0,
marginTop: ""
}, // dialog信息
mouse: { // 鼠标初始信息
x: 0,
y: 0
},
drag: { // 拖拽过程信息
x: 0,
y: 0
}
mounted(el: ElType, binding) {
if (binding.value) {
handleElShow(el)
}
// 所有的监听只为了修改data数据
header.addEventListener('mousedown', mouseDown)
document.addEventListener('mousemove', mouseMove)
document.addEventListener('mouseup', mouseUp)
window.addEventListener('resize', sizeChange)
// 边界处理,防止拖动位置溢出
function handlePosition() {
if (data.mouse.x - data.drag.x >= data.dialog.x) {
data.drag.x = data.mouse.x - data.dialog.x
}
if (data.drag.x - data.mouse.x >= data.window.width - (data.dialog.x + data.dialog.width)) {
data.drag.x = data.mouse.x + data.window.width - data.dialog.x - data.dialog.width
}
if (data.mouse.y - data.drag.y >= data.dialog.y) {
data.drag.y = data.mouse.y - data.dialog.y
}
if (data.drag.y - data.mouse.y >= data.window.height - (data.dialog.y + data.dialog.height)) {
data.drag.y = data.mouse.y + data.window.height - data.dialog.y - data.dialog.height
}
setPosition()
},
updated(el, binding) {
if (binding.value) {
handleElShow(el)
} else {
handleElHide(el)
}
// 根据data来设置拖动后的位置
function setPosition() {
let top = data.drag.y - data.mouse.y + data.dialog.y
let left = data.drag.x - data.mouse.x + data.dialog.x
dialog.style.cssText += `position: absolute; top: calc(${top}px - ${data.dialog.marginTop}); left: ${left}px;`
},
beforeUnmount(el: ElType) {
handleElHide(el)
}
}

function handleElShow(el: ElType) {
const dialog = el.querySelector('.el-dialog') as HTMLElement
if (!dialog) {
return
}
const header = el.querySelector('.el-dialog__header') as HTMLElement
const dialogMask = el.querySelector('.el-overlay') as HTMLElement
dialogMask.style.cssText += "overflow: hidden;"
header.style.cursor = 'move'
let dragStatus = false
let data = { // 数据源,不变部分为:window信息、dialog信息、mouse初始值信息,可变部分为:拖拽坐标位移
window: { // window信息
width: 0,
height: 0,
},
dialog: {
x: 0,
y: 0,
width: 0,
height: 0,
marginTop: ""
} as DataDialog, // dialog信息
mouse: { // 鼠标初始信息
x: 0,
y: 0
},
drag: { // 拖拽过程信息
x: 0,
y: 0
}
function mouseDown(e: any) {
// 获取dialog目前的位置,坐标, 以及屏幕当前的宽高
// 一切初始数据的获取应该放置于此,避免其他如:宽度修改等一系列的影响
if (e.button !== 0) {
return
}
data.window = {
width: document.body.clientWidth,
height: document.body.clientHeight
}
data.dialog = dialog.getBoundingClientRect()
data.dialog.marginTop = window.getComputedStyle(dialog).marginTop
data.mouse = {
x: e.clientX,
y: e.clientY
}
dragStatus = true
}
// 所有的监听只为了修改data数据
header.addEventListener('mousedown', mouseDown)
document.addEventListener('mousemove', mouseMove)
document.addEventListener('mouseup', mouseUp)
window.addEventListener('resize', sizeChange)
// 边界处理,防止拖动位置溢出
function handlePosition() {
if (data.mouse.x - data.drag.x >= data.dialog.x) {
data.drag.x = data.mouse.x - data.dialog.x
}
function mouseMove(e: any) {
if (dragStatus) {
data.drag = {
x: e.clientX,
y: e.clientY
}
dialogMask.style.userSelect = "none"
handlePosition()
}
if (data.drag.x - data.mouse.x >= data.window.width - (data.dialog.x + data.dialog.width)) {
data.drag.x = data.mouse.x + data.window.width - data.dialog.x - data.dialog.width
}
function mouseUp(e: any) {
dialogMask.style.userSelect = "auto"
dragStatus = false
if (data.mouse.y - data.drag.y >= data.dialog.y) {
data.drag.y = data.mouse.y - data.dialog.y
}
function sizeChange(e: any) {
// dialog.style.cssText += 'position: static';
if (data.drag.y - data.mouse.y >= data.window.height - (data.dialog.y + data.dialog.height)) {
data.drag.y = data.mouse.y + data.window.height - data.dialog.y - data.dialog.height
}
// 方便卸载使用
el.__mouseDown__ = mouseDown
el.__mouseUp__ = mouseUp
el.__mouseMove__ = mouseMove
el.__sizeChange__ = sizeChange
},
beforeUnmount(el: ElType) {
// 避免重复开销,卸载所有的监听
// 解决问题:多次创建新的实例 =》 监听不取消 =》 同时存在多个无用的监听,导致页面卡顿
document.removeEventListener('mousedown', el.__mouseDown__)
document.removeEventListener('mousemove', el.__mouseMove__)
document.removeEventListener('mouseup', el.__mouseUp__)
window.removeEventListener('resize', el.__sizeChange__)
setPosition()
}
// 根据data来设置拖动后的位置
function setPosition() {
let top = data.drag.y - data.mouse.y + data.dialog.y
let left = data.drag.x - data.mouse.x + data.dialog.x
dialog.style.cssText += `position: absolute; top: calc(${top}px - ${data.dialog.marginTop}); left: ${left}px;`
}
function mouseDown(e: any) {
// 获取dialog目前的位置,坐标, 以及屏幕当前的宽高
// 一切初始数据的获取应该放置于此,避免其他如:宽度修改等一系列的影响
if (e.button !== 0) {
return
}
data.window = {
width: document.body.clientWidth,
height: document.body.clientHeight
}
data.dialog = dialog.getBoundingClientRect()
data.dialog.marginTop = window.getComputedStyle(dialog).marginTop
data.mouse = {
x: e.clientX,
y: e.clientY
}
dragStatus = true
}
function mouseMove(e: any) {
if (dragStatus) {
data.drag = {
x: e.clientX,
y: e.clientY
}
dialogMask.style.userSelect = "none"
handlePosition()
}
}
function mouseUp(e: any) {
dialogMask.style.userSelect = "auto"
dragStatus = false
}
function sizeChange(e: any) {
// dialog.style.cssText += 'position: static';
}
// 方便卸载使用
el.__mouseDown__ = mouseDown
el.__mouseUp__ = mouseUp
el.__mouseMove__ = mouseMove
el.__sizeChange__ = sizeChange
}

function handleElHide(el: ElType) {
// 避免重复开销,卸载所有的监听
// 解决问题:多次创建新的实例 =》 监听不取消 =》 同时存在多个无用的监听,导致页面卡顿
document.removeEventListener('mousedown', el.__mouseDown__)
document.removeEventListener('mousemove', el.__mouseMove__)
document.removeEventListener('mouseup', el.__mouseUp__)
window.removeEventListener('resize', el.__sizeChange__)
}

export default drag

0 comments on commit 956bc42

Please sign in to comment.