123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581 |
- <template>
- <div
- :class="classes"
- :style="styles"
- v-move-ele.prevent.stop="{
- moveStart,
- moveElement,
- moveStop: moveElementOver
- }"
- >
- <slot></slot>
- <div class="resize-control">
- <div
- v-for="(control, index) in controlPoints"
- :key="index"
- :class="control.classes"
- v-move-ele.prevent.stop="{
- moveElement: control.movePoint,
- moveStop: control.movePointOver
- }"
- ></div>
- <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>
- import MoveEle from "../../directives/move-ele";
- export default {
- name: "element-resize",
- directives: { MoveEle },
- props: {
- value: {
- type: Object,
- required: true
- },
- active: {
- type: Array,
- default() {
- return ["r", "rb", "b", "lb", "l", "lt", "t", "rt"];
- }
- },
- move: {
- type: Boolean,
- default: true
- },
- minWidth: {
- type: Number,
- default: 30,
- validator(val) {
- return val >= 0;
- }
- },
- maxWidth: {
- type: Number,
- default: 0,
- validator(val) {
- return val >= 0;
- }
- },
- minHeight: {
- type: Number,
- default: 30,
- validator(val) {
- return val >= 0;
- }
- },
- maxHeight: {
- type: Number,
- default: 0,
- validator(val) {
- return val >= 0;
- }
- },
- fitParent: {
- type: Array,
- default() {
- return ["w", "h"];
- }
- },
- isCompact: {
- type: Boolean,
- default: false
- },
- transformFit: {
- type: Function
- },
- elementPk: {
- type: String,
- default: ""
- }
- },
- data() {
- return {
- sizePosOrigin: {
- x: 0,
- y: 0,
- w: 0,
- h: 0
- },
- offsetTopOrigin: 0,
- sizePos: {
- x: 0,
- y: 0,
- w: 0,
- h: 0
- },
- lastSizePos: {},
- initOver: false,
- controlPoints: [],
- positionType: "static",
- parentNodeSize: {
- w: 0,
- h: 0
- }
- };
- },
- computed: {
- styles() {
- return this.initOver
- ? {
- left: this.sizePos.x + "px",
- top: this.sizePos.y + "px",
- width: this.sizePos.w + "px",
- height: this.sizePos.h + "px",
- zIndex: this.sizePos.zindex,
- position: this.positionType
- }
- : {};
- },
- classes() {
- return [
- "element-resize",
- {
- "element-resize-move": this.move,
- "element-resize-init": this.initOver,
- "element-resize-compact": this.isCompact
- }
- ];
- },
- fitParentTypeWidth() {
- return this.fitParent.includes("w");
- },
- fitParentTypeHeight() {
- return this.fitParent.includes("h");
- }
- },
- created() {
- this.initControlPoints();
- },
- mounted() {
- this.initSize();
- },
- methods: {
- initControlPoints() {
- const posName = {
- l: "Left",
- r: "Right",
- t: "Top",
- b: "Bottom"
- };
- this.controlPoints = this.active.map(type => {
- const posFullName = type
- .split("")
- .map(item => {
- return posName[item];
- })
- .join("");
- return {
- classes: ["control-point", `control-point-${type}`],
- movePoint: this[`move${posFullName}Point`],
- movePointOver: this.moveOver
- };
- });
- },
- initSize() {
- const resizeDom = this.$el.childNodes[0];
- this.positionType = window.getComputedStyle(resizeDom).position;
- this.sizePos = { ...this.value };
- this.lastSizePos = { ...this.value };
- this.sizePosOrigin = { ...this.value };
- if (this.positionType === "relative")
- this.offsetTopOrigin = this.$el.offsetTop;
- this.initOver = true;
- },
- fetchValidSizePos(sizePos, actionType) {
- if (sizePos.w <= this.minWidth) {
- sizePos.w = this.minWidth;
- }
- if (this.maxWidth !== 0 && sizePos.w >= this.maxWidth) {
- sizePos.w = this.maxWidth;
- }
- if (sizePos.h <= this.minHeight) {
- sizePos.h = this.minHeight;
- }
- if (this.maxHeight !== 0 && sizePos.h >= this.maxHeight) {
- sizePos.h = this.maxHeight;
- }
- if (!this.fitParent.length) {
- this.lastSizePos = { ...sizePos };
- return sizePos;
- }
- // 不同的定位方式,计算方式有差异
- this.parentNodeSize = {
- w: this.$el.offsetParent.offsetWidth,
- h: this.$el.offsetParent.offsetHeight
- };
- if (this.fitParentTypeWidth) {
- if (sizePos.x <= 0) {
- sizePos.x = 0;
- if (actionType.includes("left")) sizePos.w = this.lastSizePos.w;
- }
- if (sizePos.x + sizePos.w > this.parentNodeSize.w) {
- sizePos.x = this.lastSizePos.x;
- sizePos.w = this.parentNodeSize.w - sizePos.x;
- }
- }
- if (this.fitParentTypeHeight) {
- if (this.positionType === "relative") {
- const elOffsetTop = this.$el.offsetTop;
- if (this.sizePosOrigin.y - sizePos.y >= this.offsetTopOrigin) {
- sizePos.h = this.lastSizePos.h;
- sizePos.y = this.sizePosOrigin.y - this.offsetTopOrigin;
- }
- if (elOffsetTop + sizePos.h >= this.parentNodeSize.h) {
- sizePos.y = this.lastSizePos.y;
- sizePos.h = this.lastSizePos.h;
- // TODO:这里如果拖动太快,会有问题
- // console.log(this.parentNodeSize.h, elOffsetTop, sizePos.h);
- }
- } else {
- if (sizePos.y <= 0) {
- sizePos.y = 0;
- if (actionType.includes("top")) sizePos.h = this.lastSizePos.h;
- }
- if (sizePos.y + sizePos.h > this.parentNodeSize.h) {
- sizePos.y = this.lastSizePos.y;
- sizePos.h = this.parentNodeSize.h - sizePos.y;
- }
- }
- }
- this.lastSizePos = { ...sizePos };
- return this.transformFit
- ? Object.assign(
- {},
- sizePos,
- this.transformFit({ id: this.elementPk, ...sizePos }, actionType)
- )
- : sizePos;
- },
- getLeftSize(left) {
- return {
- w: -left + this.sizePosOrigin.w,
- x: left + this.sizePosOrigin.x
- };
- },
- getRightSize(left) {
- return {
- w: left + this.sizePosOrigin.w
- };
- },
- getTopSize(top) {
- return {
- h: -top + this.sizePosOrigin.h,
- y: top + this.sizePosOrigin.y
- };
- },
- getBottomSize(top) {
- return {
- h: top + this.sizePosOrigin.h
- };
- },
- moveLeftPoint({ left }) {
- const sp = { ...this.sizePos, ...this.getLeftSize(left) };
- this.sizePos = { ...this.fetchValidSizePos(sp, "left") };
- this.emitChange();
- },
- moveRightPoint({ left }) {
- const sp = { ...this.sizePos, ...this.getRightSize(left) };
- this.sizePos = { ...this.fetchValidSizePos(sp, "right") };
- this.emitChange();
- },
- moveTopPoint({ top }) {
- const sp = { ...this.sizePos, ...this.getTopSize(top) };
- this.sizePos = { ...this.fetchValidSizePos(sp, "top") };
- this.emitChange();
- },
- moveBottomPoint({ top }) {
- const sp = { ...this.sizePos, ...this.getBottomSize(top) };
- this.sizePos = { ...this.fetchValidSizePos(sp, "bottom") };
- this.emitChange();
- },
- moveLeftTopPoint({ left, top }) {
- const sp = {
- ...this.sizePos,
- ...this.getLeftSize(left),
- ...this.getTopSize(top)
- };
- this.sizePos = { ...this.fetchValidSizePos(sp, "left-top") };
- this.emitChange();
- },
- moveRightTopPoint({ left, top }) {
- const sp = {
- ...this.sizePos,
- ...this.getRightSize(left),
- ...this.getTopSize(top)
- };
- this.sizePos = { ...this.fetchValidSizePos(sp, "right-top") };
- this.emitChange();
- },
- moveLeftBottomPoint({ left, top }) {
- const sp = {
- ...this.sizePos,
- ...this.getLeftSize(left),
- ...this.getBottomSize(top)
- };
- this.sizePos = { ...this.fetchValidSizePos(sp, "left-bottom") };
- this.emitChange();
- },
- moveRightBottomPoint({ left, top }) {
- const sp = {
- ...this.sizePos,
- ...this.getRightSize(left),
- ...this.getBottomSize(top)
- };
- this.sizePos = { ...this.fetchValidSizePos(sp, "right-bottom") };
- this.emitChange();
- },
- moveOver() {
- this.sizePosOrigin = { ...this.sizePos };
- this.lastSizePos = { ...this.sizePos };
- if (this.positionType === "relative")
- this.offsetTopOrigin = this.$el.offsetTop < 0 ? 0 : this.$el.offsetTop;
- this.emitChange();
- this.$emit("resize-over", this.sizePos);
- },
- moveStart() {
- this.$emit("on-click");
- },
- moveElement({ left, top }) {
- if (!this.move) return;
- const sp = {
- ...this.sizePos,
- ...{
- x: left + this.sizePosOrigin.x,
- y: top + this.sizePosOrigin.y
- }
- };
- this.sizePos = { ...this.fetchValidSizePos(sp, "move") };
- this.emitChange();
- },
- moveElementOver() {
- if (!this.move) return;
- this.moveOver();
- },
- emitChange() {
- this.$emit("input", this.sizePos);
- this.$emit("change", this.sizePos);
- }
- }
- };
- </script>
- <style lang="scss" scope>
- .element-resize {
- position: static;
- z-index: auto;
- background: #fff;
- 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: 8px;
- height: 8px;
- border-radius: 50%;
- background: #617bea;
- z-index: 99;
- &-l {
- left: 0;
- top: 50%;
- width: 5px;
- height: 20px;
- margin-top: -10px;
- margin-left: -3px;
- border-radius: 0;
- padding-top: 3px;
- cursor: w-resize;
- text-align: center;
- color: #fff;
- &::before {
- content: ".";
- display: block;
- font-size: 16px;
- line-height: 1;
- margin-top: -9px;
- }
- &::after {
- content: ".";
- display: block;
- font-size: 16px;
- line-height: 1;
- margin-top: -9px;
- }
- }
- &-lt {
- left: 0;
- top: 0;
- margin-top: -5px;
- margin-left: -5px;
- cursor: nw-resize;
- }
- &-lb {
- left: 0;
- bottom: 0;
- margin-bottom: -5px;
- margin-left: -5px;
- cursor: sw-resize;
- }
- &-r {
- right: 0;
- top: 50%;
- width: 5px;
- height: 20px;
- margin-top: -10px;
- margin-right: -3px;
- cursor: e-resize;
- border-radius: 0;
- padding-top: 3px;
- text-align: center;
- color: #fff;
- &::before {
- content: ".";
- display: block;
- font-size: 16px;
- line-height: 1;
- margin-top: -9px;
- }
- &::after {
- content: ".";
- display: block;
- font-size: 16px;
- line-height: 1;
- margin-top: -9px;
- }
- }
- &-rt {
- right: 0;
- top: 0;
- margin-top: -5px;
- margin-right: -5px;
- cursor: ne-resize;
- }
- &-rb {
- right: 0;
- bottom: 0;
- margin-bottom: -5px;
- margin-right: -5px;
- cursor: se-resize;
- }
- &-t {
- left: 50%;
- top: 0;
- width: 30px;
- height: 5px;
- border-radius: 0;
- margin-top: -3px;
- margin-left: -15px;
- cursor: n-resize;
- text-align: center;
- color: #fff;
- &::before {
- content: "...";
- display: inline-block;
- vertical-align: top;
- font-size: 16px;
- line-height: 1;
- margin-top: -10px;
- }
- }
- &-b {
- left: 50%;
- bottom: 0;
- width: 30px;
- height: 5px;
- border-radius: 0;
- margin-bottom: -3px;
- margin-left: -15px;
- cursor: s-resize;
- text-align: center;
- color: #fff;
- &::before {
- content: "...";
- display: inline-block;
- vertical-align: top;
- font-size: 16px;
- line-height: 1;
- margin-top: -10px;
- }
- }
- }
- .control-line {
- position: absolute;
- z-index: 98;
- &-left {
- height: 100%;
- left: -1px;
- top: 0;
- border-left: 1px solid #617bea;
- }
- &-right {
- height: 100%;
- right: -1px;
- top: 0;
- border-left: 1px solid #617bea;
- }
- &-top {
- width: 100%;
- left: 0;
- top: -1px;
- border-top: 1px solid #617bea;
- }
- &-bottom {
- width: 100%;
- left: 0;
- bottom: -1px;
- border-top: 1px solid #617bea;
- }
- }
- &-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>
|