核心原理就是在四条边、四个顶点加上透明的div,给不同方向提供按下移动鼠标监听 ,对应计算宽度高度、坐标变化
特性:
- 支持设置拖拽的最小宽度、最小高度、最大宽度、最大高度
- 可以双击某一条边,最大化对应方向的尺寸;再一次双击,则会恢复到原始大小
sgDragSize源码
<template><div :class="$options.name" :disabled="disabled" draggable="false"><div :class="`resize-handle resize-${a}`" draggable="false" @mousedown.stop="clickResizeHandle(a)"@dblclick.stop="dblclickResizeHandle(a)" v-for="(a, i) in sizeIndexs" :key="i"></div></div>
</template>
<script>
export default {name: 'sgDragSize',data() {return {dragSizeIndex: '',originRect: {},dblclickOriginRect: {},sizeIndexs: ['top','right','bottom','left','top-left','top-right','bottom-left','bottom-right',],}},props: ["disabled",//屏蔽"minWidth",//拖拽的最小宽度"minHeight",//拖拽的最小高度"maxWidth",//拖拽的最大宽度"maxHeight",//拖拽的最大高度],watch: {disabled: {handler(newValue, oldValue) {newValue && this.__removeWindowEvents();}, deep: true, immediate: true,},},destroyed() {this.__removeWindowEvents();},methods: {clickResizeHandle(d) {this.dragSizeIndex = d;this.mousedown(d);},dblclickResizeHandle(d) {let rect = this.$el.getBoundingClientRect();rect.width < innerWidth && rect.height < innerHeight && (this.dblclickOriginRect = rect);this.dblResize(d, rect);},__addWindowEvents() {this.__removeWindowEvents();addEventListener('mousemove', this.mousemove_window);addEventListener('mouseup', this.mouseup_window);},__removeWindowEvents() {removeEventListener('mousemove', this.mousemove_window);removeEventListener('mouseup', this.mouseup_window);},mousedown(e) {this.originRect = this.$el.getBoundingClientRect();this.originRect.bottomRightX = this.originRect.x + this.originRect.width;//右下角坐标.xthis.originRect.bottomRightY = this.originRect.y + this.originRect.height;//右下角坐标.ythis.$emit('dragStart', e);this.__addWindowEvents();},mousemove_window({ x, y }) {let minWidth = this.minWidth || 50, minHeight = this.minHeight || 50, maxWidth = this.maxWidth || innerWidth, maxHeight = this.maxHeight || innerHeight;x < 0 && (x = 0), y < 0 && (y = 0), x > innerWidth && (x = innerWidth), y > innerHeight && (y = innerHeight);let style = {};switch (this.dragSizeIndex) {case 'top-left':style.left = x;style.top = y;style.width = this.originRect.bottomRightX - x;style.width <= minWidth && (style.width = minWidth, style.left = this.originRect.bottomRightX - minWidth);style.height = this.originRect.bottomRightY - y;style.height <= minHeight && (style.height = minHeight, style.top = this.originRect.bottomRightY - minHeight);break;case 'top':style.left = this.originRect.x;style.top = y;style.width = this.originRect.width;style.height = this.originRect.bottomRightY - y;style.height <= minHeight && (style.height = minHeight, style.top = this.originRect.bottomRightY - minHeight);break;case 'top-right':style.left = this.originRect.x;style.top = y;style.width = x - this.originRect.x;style.width <= minWidth && (style.width = minWidth, style.left = this.originRect.x);style.height = this.originRect.bottomRightY - y;style.height <= minHeight && (style.height = minHeight, style.top = this.originRect.bottomRightY - minHeight);break;case 'left':style.left = x;style.top = this.originRect.y;style.width = this.originRect.bottomRightX - x;style.width <= minWidth && (style.width = minWidth, style.left = this.originRect.bottomRightX - minWidth);style.height = this.originRect.height;break;case 'right':style.left = this.originRect.x;style.top = this.originRect.y;style.width = x - this.originRect.x;style.width <= minWidth && (style.width = minWidth, style.left = this.originRect.x);style.height = this.originRect.height;break;case 'bottom-left':style.left = x;style.top = this.originRect.y;style.width = this.originRect.bottomRightX - x;style.width <= minWidth && (style.width = minWidth, style.left = this.originRect.bottomRightX - minWidth);style.height = y - this.originRect.y;style.height <= minHeight && (style.height = minHeight, style.top = this.originRect.y);break;case 'bottom':style.left = this.originRect.x;style.top = this.originRect.y;style.width = this.originRect.width;style.height = y - this.originRect.y;style.height <= minHeight && (style.height = minHeight, style.top = this.originRect.y);break;case 'bottom-right':style.left = this.originRect.x;style.top = this.originRect.y;style.width = x - this.originRect.x;style.width <= minWidth && (style.width = minWidth, style.left = this.originRect.x);style.height = y - this.originRect.y;style.height <= minHeight && (style.height = minHeight, style.top = this.originRect.y);break;default:}style.width > maxWidth && (style.width = maxWidth);style.height > maxHeight && (style.height = maxHeight);Object.keys(style).forEach(k => style[k] = `${style[k]}px`);style['transition-property'] = 'width,height';style['transition-duration'] = '0,0';this.$emit('dragging', style);},dblResize(d, rect) {let style = {};switch (d) {case 'top-left':break;case 'top':case 'bottom':style.left = this.originRect.x;style.top = rect.height >= innerHeight ? this.dblclickOriginRect.y : 0;style.width = this.originRect.width;style.height = rect.height >= innerHeight ? this.dblclickOriginRect.height : innerHeight;break;case 'top-right':break;case 'left':case 'right':style.left = rect.width >= innerWidth ? this.dblclickOriginRect.x : 0;style.top = this.originRect.y;style.width = rect.width >= innerWidth ? this.dblclickOriginRect.width : innerWidth;style.height = this.originRect.height;break;case 'bottom-left':break;case 'bottom-right':break;default:}Object.keys(style).forEach(k => style[k] = `${style[k]}px`);style['transition-property'] = 'width,height';style['transition-duration'] = '0.1s,0.1s';this.$emit('dragging', style);},mouseup_window(e) {this.$emit('dragEnd', e);this.__removeWindowEvents();},}
};
</script>
<style lang="scss">
.sgDragSize {position: absolute;width: 100%;height: 100%;left: 0;top: 0;pointer-events: none;.resize-handle {position: absolute;z-index: 100;display: block;pointer-events: auto;}&[disabled] {.resize-handle {pointer-events: none;}}.resize-top {cursor: n-resize;top: -3px;left: 0px;height: 7px;width: 100%;}.resize-right {cursor: e-resize;right: -3px;top: 0px;width: 7px;height: 100%;}.resize-bottom {cursor: s-resize;bottom: -3px;left: 0px;height: 7px;width: 100%;}.resize-left {cursor: w-resize;left: -3px;top: 0px;width: 7px;height: 100%;}.resize-top-right {cursor: ne-resize;width: 16px;height: 16px;right: -8px;top: -8px;}.resize-bottom-right {cursor: se-resize;width: 20px;height: 20px;right: -8px;bottom: -8px;background: url('/static/img/desktop/sgDragSize/resize_corner.png') no-repeat;}.resize-bottom-left {cursor: sw-resize;width: 16px;height: 16px;left: -8px;bottom: -8px;}.resize-top-left {cursor: nw-resize;width: 16px;height: 16px;left: -8px;top: -8px;}
}
</style>
应用
<template><div><div class="box" :style="style"><label>最小尺寸:宽度400px,高度200px</label><sgDragSize @dragging="d => style = d" :minWidth="400" :minHeight="200" /></div></div>
</template>
<script>
import sgDragSize from "@/vue/components/admin/sgDragSize";
export default {components: {sgDragSize,},data() {return {style: {height: '500px',width: '800px',left: '100px',top: '100px',},}},
};
</script>
<style lang="scss" scoped>
.box {position: absolute;display: flex;justify-content: center;align-items: center;background-color: #409EFF55;box-sizing: border-box;border: 1px solid #409EFF;label {user-select: none;color: #409EFF;}
}
</style>