123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485 |
- <template>
- <div
- ref="elRef"
- v-ele-move-directive.prevent.stop="{
- moveStart,
- moveElement,
- moveStop: moveElementOver,
- }"
- :class="classes"
- :style="styles"
- >
- <slot></slot>
- <div class="resize-control">
- <template v-for="(control, index) in controlPoints" :key="index">
- <div
- v-ele-move-directive.prevent.stop="{
- moveElement: control.movePoint,
- moveStop: control.movePointOver,
- }"
- :class="control.classes"
- ></div>
- </template>
- <div class="control-line control-line-left"></div>
- <div class="control-line control-line-right"></div>
- <div class="control-line control-line-top"></div>
- <div class="control-line control-line-bottom"></div>
- </div>
- </div>
- </template>
- <script setup lang="ts">
- import {
- reactive,
- ref,
- computed,
- onMounted,
- onBeforeMount,
- CSSProperties,
- } from "vue";
- import { vEleMoveDirective } from "../../directives/eleMove";
- import { objModifyAssign } from "../../utils/tool";
- import {
- defaultActive,
- defaultFitParent,
- SizeData,
- ActionType,
- FitParentItem,
- ContronItem,
- PositionData,
- } from "./types";
- defineOptions({
- name: "ElementResize",
- });
- const emit = defineEmits<{
- (event: "update:modelValue", data: SizeData): void;
- (event: "change", data: SizeData): void;
- (event: "resizeOver", data: SizeData): void;
- (event: "onClick"): void;
- }>();
- interface Props {
- modelValue: SizeData;
- active?: ActionType[];
- move?: boolean;
- minWidth?: number;
- maxWidth?: number;
- minHeight?: number;
- maxHeight?: number;
- fitParent?: FitParentItem[];
- isCompact?: boolean;
- }
- const props = withDefaults(defineProps<Props>(), {
- active: () => [...defaultActive],
- move: true,
- minWidth: 30,
- maxWidth: 0,
- minHeight: 30,
- maxHeight: 0,
- fitParent: () => [...defaultFitParent],
- isCompact: false,
- });
- const sizePosOrigin = reactive({ x: 0, y: 0, w: 0, h: 0 });
- const sizePos = reactive({ x: 0, y: 0, w: 0, h: 0 });
- const offsetTopOrigin = ref(0);
- const lastSizePos = reactive({ x: 0, y: 0, w: 0, h: 0 });
- const initOver = ref(false);
- const controlPoints = ref<ContronItem[]>([]);
- const parentNodeSize = reactive({ w: 0, h: 0 });
- const elRef = ref();
- const styles = computed(() => {
- return initOver.value
- ? {
- left: `${sizePos.x}px`,
- top: `${sizePos.y}px`,
- width: `${sizePos.w}px`,
- height: `${sizePos.h}px`,
- zIndex: props.modelValue.zindex || "auto",
- position: "absolute" as CSSProperties["position"],
- }
- : undefined;
- });
- const classes = computed(() => {
- return [
- "element-resize",
- {
- "element-resize-move": props.move,
- "element-resize-init": initOver.value,
- "element-resize-compact": props.isCompact,
- },
- ];
- });
- const fitParentTypeWidth = computed(() => {
- return props.fitParent.includes("w");
- });
- const fitParentTypeHeight = computed(() => {
- return props.fitParent.includes("h");
- });
- function initControlPoints() {
- const actions = {
- l: moveLeftPoint,
- r: moveRightPoint,
- t: moveTopPoint,
- b: moveBottomPoint,
- lt: moveLeftTopPoint,
- rt: moveRightTopPoint,
- lb: moveLeftBottomPoint,
- rb: moveRightBottomPoint,
- };
- controlPoints.value = props.active.map((type) => {
- return {
- classes: ["control-point", `control-point-${type}`],
- movePoint: actions[type],
- movePointOver: (data: PositionData) => {
- actions[type](data);
- movePointOver();
- },
- };
- });
- }
- function initSize() {
- const elDom = elRef.value as HTMLElement;
- const resizeDom = elDom.firstElementChild as Element;
- objModifyAssign(sizePos, props.modelValue);
- objModifyAssign(lastSizePos, props.modelValue);
- objModifyAssign(sizePosOrigin, props.modelValue);
- initOver.value = true;
- }
- function fetchValidSizePos(
- sizeData: SizeData,
- actionType: ActionType | "move"
- ) {
- if (sizeData.w <= props.minWidth) {
- sizeData.w = props.minWidth;
- if (actionType.includes("l"))
- sizeData.x = lastSizePos.x + lastSizePos.w - sizeData.w;
- }
- if (props.maxWidth !== 0 && sizeData.w >= props.maxWidth) {
- sizeData.w = props.maxWidth;
- }
- if (sizeData.h <= props.minHeight) {
- sizeData.h = props.minHeight;
- if (actionType.includes("t"))
- sizeData.y = lastSizePos.y + lastSizePos.h - sizeData.h;
- }
- if (props.maxHeight !== 0 && sizeData.h >= props.maxHeight) {
- sizeData.h = props.maxHeight;
- }
- if (!props.fitParent.length) {
- objModifyAssign(lastSizePos, sizeData);
- return sizeData;
- }
- // 不同的定位方式,计算方式有差异
- const elDom = elRef.value as HTMLElement;
- const elParentDom = elDom.offsetParent as HTMLElement;
- parentNodeSize.w = elParentDom.offsetWidth;
- parentNodeSize.h = elParentDom.offsetHeight;
- if (fitParentTypeWidth.value) {
- if (sizeData.x <= 0) {
- sizeData.x = 0;
- if (actionType.includes("l")) sizeData.w = lastSizePos.w + lastSizePos.x;
- }
- if (sizeData.x + sizeData.w >= parentNodeSize.w) {
- if (actionType === "move") {
- sizeData.x = parentNodeSize.w - sizeData.w;
- } else {
- sizeData.w = parentNodeSize.w - sizeData.x;
- }
- }
- }
- if (fitParentTypeHeight.value) {
- if (sizeData.y <= 0) {
- sizeData.y = 0;
- if (actionType.includes("t")) sizeData.h = lastSizePos.h + lastSizePos.y;
- }
- if (sizeData.y + sizeData.h >= parentNodeSize.h) {
- if (actionType === "move") {
- sizeData.y = parentNodeSize.h - sizeData.h;
- } else {
- sizeData.h = parentNodeSize.h - sizeData.y;
- }
- }
- }
- objModifyAssign(lastSizePos, sizeData);
- return sizeData;
- }
- function getLeftSize(left: number) {
- return {
- w: -left + sizePosOrigin.w,
- x: left + sizePosOrigin.x,
- };
- }
- function getRightSize(left: number) {
- return {
- w: left + sizePosOrigin.w,
- };
- }
- function getTopSize(top: number) {
- return {
- h: -top + sizePosOrigin.h,
- y: top + sizePosOrigin.y,
- };
- }
- function getBottomSize(top: number) {
- return {
- h: top + sizePosOrigin.h,
- };
- }
- function moveLeftPoint({ left }: Pick<PositionData, "left">) {
- const sp = { ...sizePos, ...getLeftSize(left) };
- objModifyAssign(sizePos, fetchValidSizePos(sp, "l"));
- emitChange();
- }
- function moveRightPoint({ left }: Pick<PositionData, "left">) {
- const sp = { ...sizePos, ...getRightSize(left) };
- objModifyAssign(sizePos, fetchValidSizePos(sp, "r"));
- emitChange();
- }
- function moveTopPoint({ top }: Pick<PositionData, "top">) {
- const sp = { ...sizePos, ...getTopSize(top) };
- objModifyAssign(sizePos, fetchValidSizePos(sp, "t"));
- emitChange();
- }
- function moveBottomPoint({ top }: Pick<PositionData, "top">) {
- const sp = { ...sizePos, ...getBottomSize(top) };
- objModifyAssign(sizePos, fetchValidSizePos(sp, "b"));
- emitChange();
- }
- function moveLeftTopPoint({ left, top }: PositionData) {
- const sp = {
- ...sizePos,
- ...getLeftSize(left),
- ...getTopSize(top),
- };
- objModifyAssign(sizePos, fetchValidSizePos(sp, "lt"));
- emitChange();
- }
- function moveRightTopPoint({ left, top }: PositionData) {
- const sp = {
- ...sizePos,
- ...getRightSize(left),
- ...getTopSize(top),
- };
- objModifyAssign(sizePos, fetchValidSizePos(sp, "rt"));
- emitChange();
- }
- function moveLeftBottomPoint({ left, top }: PositionData) {
- const sp = {
- ...sizePos,
- ...getLeftSize(left),
- ...getBottomSize(top),
- };
- objModifyAssign(sizePos, fetchValidSizePos(sp, "lb"));
- emitChange();
- }
- function moveRightBottomPoint({ left, top }: PositionData) {
- const sp = {
- ...sizePos,
- ...getRightSize(left),
- ...getBottomSize(top),
- };
- objModifyAssign(sizePos, fetchValidSizePos(sp, "rb"));
- emitChange();
- }
- function movePointOver() {
- objModifyAssign(sizePosOrigin, sizePos);
- objModifyAssign(lastSizePos, sizePos);
- emit("resizeOver", sizePos);
- }
- function moveStart() {
- emit("onClick");
- }
- function moveElement({ left, top }: PositionData) {
- if (!props.move) return;
- const sp = {
- ...sizePos,
- ...{
- x: left + sizePosOrigin.x,
- y: top + sizePosOrigin.y,
- },
- };
- objModifyAssign(sizePos, fetchValidSizePos(sp, "move"));
- emitChange();
- }
- function moveElementOver({ left, top }: PositionData) {
- if (!props.move) return;
- moveElement({ left, top });
- objModifyAssign(sizePosOrigin, sizePos);
- objModifyAssign(lastSizePos, sizePos);
- emit("resizeOver", sizePos);
- }
- function emitChange() {
- emit("update:modelValue", sizePos);
- emit("change", sizePos);
- }
- onMounted(() => {
- initSize();
- });
- onBeforeMount(() => {
- initControlPoints();
- });
- </script>
- <style lang="less" scoped>
- .element-resize {
- position: static;
- z-index: auto;
- background: transparent;
- box-sizing: content-box;
- &-move {
- cursor: move;
- }
- &-init {
- > div:first-child {
- width: 100% !important;
- height: 100% !important;
- position: relative !important;
- top: 0 !important;
- left: 0 !important;
- overflow: hidden;
- }
- }
- .control-point {
- position: absolute;
- width: 12px;
- height: 12px;
- background: #f53f3f;
- z-index: 99;
- &-l {
- left: 0;
- top: 50%;
- width: 12px;
- height: 12px;
- margin-top: -6px;
- border-radius: 0;
- cursor: w-resize;
- }
- &-lt {
- left: 0;
- top: 0;
- cursor: nw-resize;
- }
- &-lb {
- left: 0;
- bottom: 0;
- cursor: sw-resize;
- }
- &-r {
- right: 0;
- top: 50%;
- margin-top: -6px;
- cursor: e-resize;
- }
- &-rt {
- right: 0;
- top: 0;
- cursor: ne-resize;
- }
- &-rb {
- right: 0;
- bottom: 0;
- cursor: se-resize;
- }
- &-t {
- left: 50%;
- top: 0;
- margin-left: -6px;
- cursor: n-resize;
- }
- &-b {
- left: 50%;
- bottom: 0;
- margin-left: -6px;
- cursor: s-resize;
- }
- }
- .control-line {
- position: absolute;
- z-index: 98;
- &-left {
- height: 100%;
- left: 0;
- top: 0;
- border-left: 4px solid #f53f3f;
- }
- &-right {
- height: 100%;
- right: 0;
- top: 0;
- border-left: 4px solid #f53f3f;
- }
- &-top {
- width: 100%;
- left: 0;
- top: 0;
- border-top: 4px solid #f53f3f;
- }
- &-bottom {
- width: 100%;
- left: 0;
- bottom: 0;
- border-top: 4px solid #f53f3f;
- }
- }
- &-compact {
- .control-line {
- &-left {
- left: 0;
- border-left: 1px dashed #bbb;
- }
- &-right {
- right: 0;
- border-left: 1px dashed #bbb;
- }
- &-top {
- top: 0;
- border-top: 1px dashed #bbb;
- }
- &-bottom {
- bottom: 0;
- border-top: 1px dashed #bbb;
- }
- }
- }
- }
- </style>
|