useLayer
用于实现可调整各个方向大小以及位置的组合式函数
注意
目标元素需要开启绝对定位 absolute 或 fixed
使用示例
点我查看代码
vue
<script lang="ts" setup>
import { useLayer } from '@summeruse/ui'
import { NCheckbox, NForm, NFormItem, NInputNumber, NSelect } from 'naive-ui'
import { computed, ref } from 'vue'
const container = ref<HTMLElement>()
const header = ref<HTMLElement>()
const content = ref<HTMLElement>()
const parentRef = ref<HTMLElement>()
const minWidth = ref(100)
const minHeight = ref(100)
const maxWidth = ref(600)
const maxHeight = ref(150)
const disabledResize = ref(false)
const disabledDrag = ref(false)
const initRect = ref({
width: 300,
height: 100,
x: 850,
y: 500,
})
const isRatio = ref(true)
const ratio = computed(() => {
if (isRatio.value)
return initRect.value.width / initRect.value.height
else
return undefined
})
const parentValue = ref('body')
const parentOptions = [{
label: 'parent',
value: 'parent',
}, {
label: 'body',
value: 'body',
}]
const parent = computed(() => {
if (parentValue.value === 'parent') {
return parentRef.value
}
return document.body
})
const allowOverParent = ref(false)
const dragValue = ref('container')
const dragOptions = [{
label: 'container',
value: 'container',
}, {
label: 'header',
value: 'header',
}, {
label: 'content',
value: 'content',
}]
const dragElement = computed(() => {
if (dragValue.value === 'header') {
return header.value
}
else if (dragValue.value === 'content') {
return content.value
}
return container.value
})
const directions = ref({
'left': true,
'right': true,
'top': true,
'bottom': true,
'top-left': true,
'top-right': true,
'bottom-left': true,
'bottom-right': true,
})
const { rect } = useLayer(container, {
directions,
initRect,
minWidth,
minHeight,
maxWidth,
maxHeight,
ratio,
disabledResize,
disabledDrag,
parent,
allowOverParent,
dragElement,
})
const style = computed(() => {
return {
width: `${rect.value.width}px`,
height: `${rect.value.height}px`,
left: `${rect.value.x}px`,
top: `${rect.value.y}px`,
}
})
</script>
<template>
<Teleport to="body">
<div ref="parentRef" class="fixed w-800px h-350px bg-#abf5 z--1 top-400px left-350px pointer-events-none">
parent
</div>
</Teleport>
<NForm label-placement="left" label-width="120px" class="flex flex-wrap">
<NFormItem label="Disabled Resize">
<NCheckbox v-model:checked="disabledResize" />
</NFormItem>
<NFormItem label="Disabled Drag">
<NCheckbox v-model:checked="disabledDrag" />
</NFormItem>
<NFormItem label="Is Ratio">
<NCheckbox v-model:checked="isRatio" />
</NFormItem>
<NFormItem label="Over Parent">
<NCheckbox v-model:checked="allowOverParent" />
</NFormItem>
<NFormItem label="parent">
<NSelect v-model:value="parentValue" :options="parentOptions" />
</NFormItem>
<NFormItem label="drag Element">
<NSelect v-model:value="dragValue" :options="dragOptions" />
</NFormItem>
<NFormItem label="Resize">
<NCheckbox v-model:checked="directions.left">
left
</NCheckbox>
<NCheckbox v-model:checked="directions.right">
right
</NCheckbox>
<NCheckbox v-model:checked="directions.top">
top
</NCheckbox>
<NCheckbox v-model:checked="directions.bottom">
bottom
</NCheckbox>
</NFormItem>
<NFormItem label="directions">
<NCheckbox v-model:checked="directions['top-left']">
top-left
</NCheckbox>
<NCheckbox v-model:checked="directions['top-right']">
top-right
</NCheckbox>
<NCheckbox v-model:checked="directions['bottom-left']">
bottom-left
</NCheckbox>
<NCheckbox v-model:checked="directions['bottom-right']">
bottom-right
</NCheckbox>
</NFormItem>
<NFormItem label="Init Width">
<NInputNumber v-model:value="initRect.width" />
</NFormItem>
<NFormItem label="Init Height">
<NInputNumber v-model:value="initRect.height" />
</NFormItem>
<NFormItem label="Init X">
<NInputNumber v-model:value="initRect.x" />
</NFormItem>
<NFormItem label="Init Y">
<NInputNumber v-model:value="initRect.y" />
</NFormItem>
<NFormItem label="Min Width">
<NInputNumber v-model:value="minWidth" />
</NFormItem>
<NFormItem label="Min Height">
<NInputNumber v-model:value="minHeight" />
</NFormItem>
<NFormItem label="Max Width">
<NInputNumber v-model:value="maxWidth" />
</NFormItem>
<NFormItem label="Max Height">
<NInputNumber v-model:value="maxHeight" />
</NFormItem>
</NForm>
<Teleport to="body">
<div ref="container" class="fixed flex flex-col z-1000 bg-black text-#fff" :style>
<div ref="header" class="h-20px bg-#abf">
header
</div>
<div ref="content" class="h-100%">
{{ rect.width }} * {{ rect.height }}
</div>
</div>
</Teleport>
</template>
源代码
点我查看代码
ts
export * from './types'
export * from './useLayer'
ts
import type { ComputedRef, Ref } from 'vue'
import type { Rect } from './types'
function initMousedownData({
e,
rect,
minWidth,
minHeight,
maxWidth,
maxHeight,
minX,
minY,
maxBottom,
maxRight,
ratio,
}:
{
e: MouseEvent
rect: Ref<Rect>
minWidth: Ref<number>
minHeight: Ref<number>
maxWidth: Ref<number>
maxHeight: Ref<number>
minX: Ref<number>
minY: Ref<number>
maxBottom: Ref<number>
maxRight: Ref<number>
ratio: ComputedRef<number | undefined>
isResize: Ref<boolean>
}) {
const startX = e.clientX
const startY = e.clientY
const x = rect.value.x
const y = rect.value.y
const height = rect.value.height
const width = rect.value.width
const startLeft = x + width
const startTop = y + height
const _minX = minX.value
const _maxBottom = maxBottom.value
const _maxRight = maxRight.value
const _minY = minY.value
const _ratio = ratio.value
const _minWidth = _ratio ? Math.max(minWidth.value, minHeight.value * _ratio) : minWidth.value
const _maxWidth = _ratio ? Math.min(maxWidth.value, maxHeight.value * _ratio) : maxWidth.value
const _minHeight = _ratio ? Math.max(minHeight.value, minWidth.value / _ratio) : minHeight.value
const _maxHeight = _ratio ? Math.min(maxHeight.value, maxWidth.value / _ratio) : maxHeight.value
return {
startX,
startY,
x,
y,
height,
width,
startLeft,
startTop,
_minX,
_maxBottom,
_maxRight,
_minY,
_ratio,
_minWidth,
_maxWidth,
_minHeight,
_maxHeight,
}
}
function _initResize({ isResize }:
{
isResize: Ref<boolean>
}) {
isResize.value = true
document.body.classList.add('summer-use-un-select')
const close = () => {
isResize.value = false
document.body.classList.remove('summer-use-un-select')
}
return {
close,
}
}
/** @Description: 左边拉伸 */
export function resizeLeft(
data:
{
e: MouseEvent
rect: Ref<Rect>
minWidth: Ref<number>
minHeight: Ref<number>
maxWidth: Ref<number>
maxHeight: Ref<number>
minX: Ref<number>
minY: Ref<number>
maxBottom: Ref<number>
maxRight: Ref<number>
ratio: ComputedRef<number | undefined>
isResize: Ref<boolean>
},
) {
const {
startX,
x,
y,
height,
width,
startLeft,
_minX,
_maxBottom,
_minY,
_ratio,
_minWidth,
_maxWidth,
} = initMousedownData(data)
const { isResize, rect } = data
const { close } = _initResize({ isResize })
const mouseMoveHandler = (e: MouseEvent) => {
const moveX = e.clientX - startX
let nextWidth = width - moveX
let nextX = x + moveX
let nextHeight = height
let nextY = y
if (nextWidth > _maxWidth) {
nextWidth = _maxWidth
nextX = startLeft - nextWidth
}
if (nextX < _minX) {
nextX = _minX
nextWidth = width - (nextX - x)
}
if (nextWidth < _minWidth) {
nextWidth = _minWidth
nextX = startLeft - nextWidth
}
if (_ratio) {
nextHeight = nextWidth / _ratio
nextY = y - (nextHeight - height) / 2
if (nextY < _minY) {
nextY = _minY
nextHeight = (y - nextY) * 2 + height
nextWidth = nextHeight * _ratio
nextX = startLeft - nextWidth
}
if ((nextY + nextHeight) > _maxBottom) {
nextY = y - (_maxBottom - y - height)
nextHeight = _maxBottom - nextY
nextWidth = nextHeight * _ratio
nextX = startLeft - nextWidth
}
}
rect.value.height = nextHeight
rect.value.width = nextWidth
rect.value.x = nextX
rect.value.y = nextY
}
const mouseUpHandler = () => {
close()
document.removeEventListener('mousemove', mouseMoveHandler)
document.removeEventListener('mouseup', mouseUpHandler)
}
document.addEventListener('mousemove', mouseMoveHandler)
document.addEventListener('mouseup', mouseUpHandler)
}
/** @Description: 右边拉伸 */
export function resizeRight(
data:
{
e: MouseEvent
rect: Ref<Rect>
minWidth: Ref<number>
minHeight: Ref<number>
maxWidth: Ref<number>
maxHeight: Ref<number>
minX: Ref<number>
minY: Ref<number>
maxBottom: Ref<number>
maxRight: Ref<number>
ratio: ComputedRef<number | undefined>
isResize: Ref<boolean>
},
) {
const {
startX,
x,
y,
height,
width,
_maxRight,
_maxBottom,
_minY,
_ratio,
_minWidth,
_maxWidth,
} = initMousedownData(data)
const { isResize, rect } = data
const { close } = _initResize({ isResize })
const mouseMoveHandler = (e: MouseEvent) => {
const moveX = e.clientX - startX
let nextWidth = width + moveX
let nextHeight = height
let nextY = y
if (nextWidth > _maxWidth) {
nextWidth = _maxWidth
}
if (nextWidth < _minWidth) {
nextWidth = _minWidth
}
if (nextWidth + x > _maxRight) {
nextWidth = _maxRight - x
}
if (_ratio) {
nextHeight = nextWidth / _ratio
nextY = y - (nextHeight - height) / 2
if (nextY < _minY) {
nextY = _minY
nextHeight = (y - nextY) * 2 + height
nextWidth = nextHeight * _ratio
}
if ((nextY + nextHeight) > _maxBottom) {
nextY = y - (_maxBottom - y - height)
nextHeight = _maxBottom - nextY
nextWidth = nextHeight * _ratio
}
}
rect.value.height = nextHeight
rect.value.width = nextWidth
rect.value.y = nextY
}
const mouseUpHandler = () => {
close()
document.removeEventListener('mousemove', mouseMoveHandler)
document.removeEventListener('mouseup', mouseUpHandler)
}
document.addEventListener('mousemove', mouseMoveHandler)
document.addEventListener('mouseup', mouseUpHandler)
}
/** @Description: 上边拉伸 */
export function resizeTop(data:
{
e: MouseEvent
rect: Ref<Rect>
minWidth: Ref<number>
minHeight: Ref<number>
maxWidth: Ref<number>
maxHeight: Ref<number>
minX: Ref<number>
minY: Ref<number>
maxBottom: Ref<number>
maxRight: Ref<number>
ratio: ComputedRef<number | undefined>
isResize: Ref<boolean>
}) {
const {
startY,
x,
y,
height,
width,
startLeft,
startTop,
_minX,
_maxRight,
_minY,
_ratio,
_minHeight,
_maxHeight,
} = initMousedownData(data)
const { isResize, rect } = data
const { close } = _initResize({ isResize })
const mouseMoveHandler = (e: MouseEvent) => {
const moveY = e.clientY - startY
let nextHeight = height - moveY
let nextY = y + moveY
let nextWidth = width
let nextX = x
if (nextHeight + nextY >= startTop) {
nextHeight = Math.max(nextHeight, _minHeight)
nextY = startTop - nextHeight
nextY = Math.min(nextY, startTop)
}
if (nextY < _minY) {
nextY = _minY
nextHeight = startTop - nextY
}
if (nextHeight > _maxHeight) {
nextHeight = Math.min(nextHeight, _maxHeight)
nextY = startTop - nextHeight
}
if (_ratio) {
nextWidth = nextHeight * _ratio
nextX = x - (nextWidth - width) / 2
if (nextX < _minX) {
nextX = _minX
nextWidth = (startLeft - _minX - width) * 2 + width
nextHeight = nextWidth / _ratio
nextY = startTop - nextHeight
}
if (nextX + nextWidth > _maxRight) {
nextWidth = (_maxRight - x - width) * 2 + width
nextX = _maxRight - nextWidth
nextHeight = nextWidth / _ratio
nextY = startTop - nextHeight
}
}
rect.value.height = nextHeight
rect.value.y = nextY
rect.value.width = nextWidth
rect.value.x = nextX
}
const mouseUpHandler = () => {
close()
document.removeEventListener('mousemove', mouseMoveHandler)
document.removeEventListener('mouseup', mouseUpHandler)
}
document.addEventListener('mousemove', mouseMoveHandler)
document.addEventListener('mouseup', mouseUpHandler)
}
/** @Description: 下边拉伸 */
export function resizeBottom(data:
{
e: MouseEvent
rect: Ref<Rect>
minWidth: Ref<number>
minHeight: Ref<number>
maxWidth: Ref<number>
maxHeight: Ref<number>
minX: Ref<number>
minY: Ref<number>
maxBottom: Ref<number>
maxRight: Ref<number>
ratio: ComputedRef<number | undefined>
isResize: Ref<boolean>
}) {
const {
startY,
x,
y,
height,
width,
startLeft,
_minX,
_maxBottom,
_maxRight,
_ratio,
_minHeight,
_maxHeight,
} = initMousedownData(data)
const { isResize, rect } = data
const { close } = _initResize({ isResize })
const mouseMoveHandler = (e: MouseEvent) => {
const moveY = e.clientY - startY
let nextHeight = height + moveY
let nextWidth = width
let nextX = x
if (nextHeight > _maxHeight) {
nextHeight = Math.min(nextHeight, _maxHeight)
}
if (nextHeight < _minHeight) {
nextHeight = Math.max(nextHeight, _minHeight)
}
if (nextHeight + y >= _maxBottom) {
nextHeight = _maxBottom - y
}
if (_ratio) {
nextWidth = nextHeight * _ratio
nextX = x - (nextWidth - width) / 2
if (nextX < _minX) {
nextX = _minX
nextWidth = (startLeft - _minX - width) * 2 + width
nextHeight = nextWidth / _ratio
}
if (nextX + nextWidth > _maxRight) {
nextWidth = (_maxRight - x - width) * 2 + width
nextX = _maxRight - nextWidth
nextHeight = nextWidth / _ratio
}
}
rect.value.height = nextHeight
rect.value.width = nextWidth
rect.value.x = nextX
}
const mouseUpHandler = () => {
close()
document.removeEventListener('mousemove', mouseMoveHandler)
document.removeEventListener('mouseup', mouseUpHandler)
}
document.addEventListener('mousemove', mouseMoveHandler)
document.addEventListener('mouseup', mouseUpHandler)
}
/* @Description: 左上角拉伸 */
export function resizeTopLeft(data:
{
e: MouseEvent
rect: Ref<Rect>
minWidth: Ref<number>
minHeight: Ref<number>
maxWidth: Ref<number>
maxHeight: Ref<number>
minX: Ref<number>
minY: Ref<number>
maxBottom: Ref<number>
maxRight: Ref<number>
ratio: ComputedRef<number | undefined>
isResize: Ref<boolean>
}) {
const {
startX,
startY,
x,
y,
height,
width,
startTop,
startLeft,
_maxWidth,
_minWidth,
_maxRight,
_minX,
_minY,
_ratio,
_minHeight,
_maxHeight,
} = initMousedownData(data)
const { isResize, rect } = data
const { close } = _initResize({ isResize })
const mouseMoveHandler = (e: MouseEvent) => {
const moveX = e.clientX - startX
const moveY = e.clientY - startY
let nextWidth = width - moveX
let nextHeight = height - moveY
let nextY = y + moveY
let nextX = x + moveX
if (nextWidth > _maxWidth) {
nextWidth = _maxWidth
nextX = startLeft - nextWidth
}
if (nextWidth < _minWidth) {
nextWidth = _minWidth
nextX = startLeft - nextWidth
}
if (nextHeight + nextY >= startTop) {
nextHeight = Math.max(nextHeight, _minHeight)
nextY = startTop - nextHeight
nextY = Math.min(nextY, startTop)
}
if (nextY < _minY) {
nextY = _minY
nextHeight = startTop - nextY
}
if (nextHeight > _maxHeight) {
nextHeight = Math.min(nextHeight, _maxHeight)
nextY = startTop - nextHeight
}
if (_ratio) {
const _nextWidth = nextHeight * _ratio
nextWidth = Math.max(_nextWidth, nextWidth)
nextHeight = nextWidth / _ratio
nextY = startTop - nextHeight
nextX = startLeft - nextWidth
if (nextWidth + x > _maxRight) {
nextWidth = _maxRight - x
nextHeight = nextWidth / _ratio
nextY = startTop - nextHeight
}
if (nextY < _minY) {
nextY = _minY
nextHeight = startTop - nextY
nextWidth = nextHeight * _ratio
nextX = startLeft - nextWidth
}
if (nextX < _minX) {
nextX = _minX
nextWidth = (startLeft - _minX - width) + width
nextHeight = nextWidth / _ratio
nextY = startTop - nextHeight
}
}
rect.value.height = nextHeight
rect.value.width = nextWidth
rect.value.x = nextX
rect.value.y = nextY
}
const mouseUpHandler = () => {
close()
document.removeEventListener('mousemove', mouseMoveHandler)
document.removeEventListener('mouseup', mouseUpHandler)
}
document.addEventListener('mousemove', mouseMoveHandler)
document.addEventListener('mouseup', mouseUpHandler)
}
/** @Description: 右上角拉伸 */
export function resizeTopRight(data:
{
e: MouseEvent
rect: Ref<Rect>
minWidth: Ref<number>
minHeight: Ref<number>
maxWidth: Ref<number>
maxHeight: Ref<number>
minX: Ref<number>
minY: Ref<number>
maxBottom: Ref<number>
maxRight: Ref<number>
ratio: ComputedRef<number | undefined>
isResize: Ref<boolean>
}) {
const {
startX,
startY,
x,
y,
height,
width,
startTop,
_maxWidth,
_minWidth,
_maxRight,
_minY,
_ratio,
_minHeight,
_maxHeight,
} = initMousedownData(data)
const { isResize, rect } = data
const { close } = _initResize({ isResize })
const mouseMoveHandler = (e: MouseEvent) => {
const moveX = e.clientX - startX
const moveY = e.clientY - startY
let nextWidth = width + moveX
let nextHeight = height - moveY
let nextY = y + moveY
if (nextWidth > _maxWidth) {
nextWidth = _maxWidth
}
if (nextWidth < _minWidth) {
nextWidth = _minWidth
}
if (nextWidth + x > _maxRight) {
nextWidth = _maxRight - x
}
if (nextHeight + nextY >= startTop) {
nextHeight = Math.max(nextHeight, _minHeight)
nextY = startTop - nextHeight
nextY = Math.min(nextY, startTop)
}
if (nextY < _minY) {
nextY = _minY
nextHeight = startTop - nextY
}
if (nextHeight > _maxHeight) {
nextHeight = Math.min(nextHeight, _maxHeight)
nextY = startTop - nextHeight
}
if (_ratio) {
const _nextWidth = nextHeight * _ratio
nextWidth = Math.max(_nextWidth, nextWidth)
nextHeight = nextWidth / _ratio
nextY = startTop - nextHeight
if (nextWidth + x > _maxRight) {
nextWidth = _maxRight - x
nextHeight = nextWidth / _ratio
nextY = startTop - nextHeight
}
if (nextY < _minY) {
nextY = _minY
nextHeight = startTop - nextY
nextWidth = nextHeight * _ratio
}
}
rect.value.height = nextHeight
rect.value.width = nextWidth
rect.value.y = nextY
}
const mouseUpHandler = () => {
close()
document.removeEventListener('mousemove', mouseMoveHandler)
document.removeEventListener('mouseup', mouseUpHandler)
}
document.addEventListener('mousemove', mouseMoveHandler)
document.addEventListener('mouseup', mouseUpHandler)
}
/** @Description: 左下角拉伸 */
export function resizeBottomLeft(data:
{
e: MouseEvent
rect: Ref<Rect>
minWidth: Ref<number>
minHeight: Ref<number>
maxWidth: Ref<number>
maxHeight: Ref<number>
minX: Ref<number>
minY: Ref<number>
maxBottom: Ref<number>
maxRight: Ref<number>
ratio: ComputedRef<number | undefined>
isResize: Ref<boolean>
}) {
const {
startX,
startY,
x,
y,
height,
width,
startLeft,
_maxWidth,
_minWidth,
_maxBottom,
_minX,
_ratio,
_minHeight,
_maxHeight,
} = initMousedownData(data)
const { isResize, rect } = data
const { close } = _initResize({ isResize })
const mouseMoveHandler = (e: MouseEvent) => {
const moveX = e.clientX - startX
const moveY = e.clientY - startY
let nextWidth = width - moveX
let nextHeight = height + moveY
const nextY = y
let nextX = x + moveX
if (nextWidth > _maxWidth) {
nextWidth = _maxWidth
nextX = startLeft - nextWidth
}
if (nextWidth < _minWidth) {
nextWidth = _minWidth
nextX = startLeft - nextWidth
}
if (nextHeight < _minHeight) {
nextHeight = _minHeight
}
if (nextHeight > _maxHeight) {
nextHeight = Math.min(nextHeight, _maxHeight)
}
if (nextHeight + y > _maxBottom) {
nextHeight = _maxBottom - y
}
if (_ratio) {
const _nextWidth = nextHeight * _ratio
nextWidth = Math.max(_nextWidth, nextWidth)
nextHeight = nextWidth / _ratio
nextX = startLeft - nextWidth
if (nextHeight + y > _maxBottom) {
nextHeight = _maxBottom - y
nextWidth = nextHeight * _ratio
nextX = startLeft - nextWidth
}
if (nextX < _minX) {
nextX = _minX
nextWidth = (startLeft - _minX - width) + width
nextHeight = nextWidth / _ratio
nextX = startLeft - nextWidth
}
}
rect.value.height = nextHeight
rect.value.width = nextWidth
rect.value.y = nextY
rect.value.x = nextX
}
const mouseUpHandler = () => {
close()
document.removeEventListener('mousemove', mouseMoveHandler)
document.removeEventListener('mouseup', mouseUpHandler)
}
document.addEventListener('mousemove', mouseMoveHandler)
document.addEventListener('mouseup', mouseUpHandler)
}
/** @Description: 右下角拉伸 */
export function resizeBottomRight(data:
{
e: MouseEvent
rect: Ref<Rect>
minWidth: Ref<number>
minHeight: Ref<number>
maxWidth: Ref<number>
maxHeight: Ref<number>
minX: Ref<number>
minY: Ref<number>
maxBottom: Ref<number>
maxRight: Ref<number>
ratio: ComputedRef<number | undefined>
isResize: Ref<boolean>
}) {
const {
startX,
startY,
x,
y,
height,
width,
_maxRight,
_maxWidth,
_minWidth,
_maxBottom,
_ratio,
_minHeight,
_maxHeight,
} = initMousedownData(data)
const { isResize, rect } = data
const { close } = _initResize({ isResize })
const mouseMoveHandler = (e: MouseEvent) => {
const moveX = e.clientX - startX
const moveY = e.clientY - startY
let nextWidth = width + moveX
let nextHeight = height + moveY
const nextY = y
if (nextWidth > _maxWidth) {
nextWidth = _maxWidth
}
if (nextWidth < _minWidth) {
nextWidth = _minWidth
}
if (nextHeight < _minHeight) {
nextHeight = _minHeight
}
if (nextHeight > _maxHeight) {
nextHeight = Math.min(nextHeight, _maxHeight)
}
if (nextHeight + y > _maxBottom) {
nextHeight = _maxBottom - y
}
if (nextWidth + x > _maxRight) {
nextWidth = _maxRight - x
}
if (_ratio) {
const _nextWidth = nextHeight * _ratio
nextWidth = Math.max(_nextWidth, nextWidth)
nextHeight = nextWidth / _ratio
if (nextHeight + y > _maxBottom) {
nextHeight = _maxBottom - y
nextWidth = nextHeight * _ratio
}
if (nextWidth + x > _maxRight) {
nextWidth = _maxRight - x
nextHeight = nextWidth / _ratio
}
}
rect.value.height = nextHeight
rect.value.width = nextWidth
rect.value.y = nextY
}
const mouseUpHandler = () => {
close()
document.removeEventListener('mousemove', mouseMoveHandler)
document.removeEventListener('mouseup', mouseUpHandler)
}
document.addEventListener('mousemove', mouseMoveHandler)
document.addEventListener('mouseup', mouseUpHandler)
}
ts
import type { Ref } from 'vue'
import type { Rect } from './types'
export function drag(
{ e, rect, minX, maxRight, minY, maxBottom }: {
e: MouseEvent
rect: Ref<Rect>
minX: Ref<number>
maxRight: Ref<number>
minY: Ref<number>
maxBottom: Ref<number>
},
) {
const startX = e.clientX
const startY = e.clientY
const startLeft = rect.value.x
const startTop = rect.value.y
const width = rect.value.width
const height = rect.value.height
document.body.classList.add('summer-use-un-select')
const mouseMoveHandler = (e: MouseEvent) => {
let x = e.clientX - startX + startLeft
let y = e.clientY - startY + startTop
if (x < minX.value) {
x = minX.value
}
if (x > maxRight.value - width) {
x = maxRight.value - width
}
if (y < minY.value) {
y = minY.value
}
if (y > maxBottom.value - height) {
y = maxBottom.value - height
}
rect.value.x = x
rect.value.y = y
}
const mouseUpHandler = () => {
document.body.classList.remove('summer-use-un-select')
document.removeEventListener('mousemove', mouseMoveHandler)
document.removeEventListener('mouseup', mouseUpHandler)
}
document.addEventListener('mousemove', mouseMoveHandler)
document.addEventListener('mouseup', mouseUpHandler)
}
scss
.summer-use-resize {
width: 100%;
height: 100%;
position: absolute;
pointer-events: none;
left: 0;
top: 0;
* {
pointer-events: auto;
z-index: 99999;
}
.summer-use-resize-bottom-right {
position: absolute;
right: -5px;
bottom: -5px;
width: 10px;
height: 10px;
cursor: se-resize;
}
.summer-use-resize-bottom-left {
position: absolute;
left: -5px;
bottom: -5px;
width: 10px;
height: 10px;
cursor: sw-resize;
}
.summer-use-resize-top-right {
position: absolute;
right: -5px;
top: -5px;
width: 10px;
height: 10px;
cursor: ne-resize;
}
.summer-use-resize-top-left {
position: absolute;
left: -5px;
top: -5px;
width: 10px;
height: 10px;
cursor: nw-resize;
}
.summer-use-resize-top {
position: absolute;
left: 5px;
right: 5px;
top: -5px;
height: 10px;
cursor: n-resize;
}
.summer-use-resize-bottom {
position: absolute;
left: 5px;
right: 5px;
bottom: -5px;
height: 10px;
cursor: s-resize;
}
.summer-use-resize-left {
position: absolute;
left: -5px;
top: 5px;
bottom: 5px;
width: 10px;
cursor: w-resize;
}
.summer-use-resize-right {
position: absolute;
right: -5px;
top: 5px;
bottom: 5px;
width: 10px;
cursor: e-resize;
}
}
.summer-use-resize-disabled {
* {
pointer-events: none;
}
}
.summer-use-resize-direction-disabled{
pointer-events: none;
}
.summer-use-un-select {
user-select: none;
}
.summer-use-drag {
cursor: move;
}
类型定义
点我查看代码
ts
import type { MaybeRefOrGetter } from 'vue'
export type ResizeDirection = 'left' | 'right' | 'top' | 'bottom' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
export interface Directions {
'left'?: boolean
'right'?: boolean
'top'?: boolean
'bottom'?: boolean
'top-left'?: boolean
'top-right'?: boolean
'bottom-left'?: boolean
'bottom-right'?: boolean
}
export interface Rect {
height: number
width: number
x: number
y: number
}
export interface LayerOptions {
// 方向
directions?: MaybeRefOrGetter<Directions | undefined>
// 初始位置
initRect?: MaybeRefOrGetter<Rect>
// 拖动元素
dragElement?: MaybeRefOrGetter<HTMLElement | undefined>
// 禁止拉伸
disabledResize?: MaybeRefOrGetter<boolean>
// 禁止拖动
disabledDrag?: MaybeRefOrGetter<boolean>
// 最小宽度
minWidth?: MaybeRefOrGetter<number | undefined>
// 最小高度
minHeight?: MaybeRefOrGetter<number | undefined>
// 最大宽度
maxWidth?: MaybeRefOrGetter<number | undefined>
// 最大高度
maxHeight?: MaybeRefOrGetter<number | undefined>
// 宽高比
ratio?: MaybeRefOrGetter<number | undefined>
// 限位元素
parent?: MaybeRefOrGetter<HTMLElement | undefined>
// 允许拉伸到父元素外面
allowOverParent?: MaybeRefOrGetter<boolean>
}