Browse Source

撤销与恢复

master
1549469775 4 years ago
parent
commit
b3d8664734
  1. 3
      src/assets/style/global.scss
  2. 27
      src/data/component-list.js
  3. 4
      src/main.js
  4. 26
      src/ui/detail/detail.vue
  5. 50
      src/ui/editor/MakeLine.vue
  6. 289
      src/ui/editor/Shape.vue
  7. 118
      src/ui/editor/editor.vue
  8. 34
      src/ui/header/header.vue
  9. 17
      src/ui/header/sub.vue
  10. 3
      src/views/home/index.vue

3
src/assets/style/global.scss

@ -1,3 +1,6 @@
html,body,#app{
height: 100%;
}
*{
user-select: none;
}

27
src/data/component-list.js

@ -7,10 +7,29 @@ let list = [
props: {},
id: "customID",
style: {
color: 'red',
left: 0,
top: 0,
width: 80,
height: 32,
zIndex: 1
},
},
{
name: "img",
describe: "图片",
type: "component",
slot: [],
props: {
draggable:"false",
src: 'https://scpic.chinaz.net/files/pic/pic9/202101/bpic22299.jpg'
},
id: "imgID",
style: {
left: 0,
top: 0,
width: 380,
height: 200,
},
},
{
@ -34,7 +53,9 @@ let list = [
describe: "输入框",
type: "component",
slot: [],
props: {},
props: {
placeholder:'请输入'
},
id: "inputID",
style: {
height: 32,
@ -126,5 +147,9 @@ let list = [
},
},
];
list = list.map(v=>{
v.origin = JSON.parse(JSON.stringify(v.style));
return v
})
export default list;

4
src/main.js

@ -13,12 +13,12 @@ Vue.config.productionTip = process.env.NODE_ENV === 'production' ? true : false;
Vue.use(toast);
Vue.prototype.$computeStyle= function(style){
Vue.prototype.$computeStyle= function(style,isDefault=false){
let myStyle = cloneDeep(style);
let attr = ["left", "width", "height", "top", "right", "bottom"];
let attrStr = ["backgroundColor", "color","position",'zIndex'];
Object.keys(style).forEach((v) => {
if (attr.indexOf(v) != -1 && typeof style[v] == "number") {
if (!isDefault&&attr.indexOf(v) != -1 && typeof style[v] == "number") {
myStyle[v] = style[v] + "px";
}
if (attrStr.indexOf(v) != -1) {

26
src/ui/detail/detail.vue

@ -3,13 +3,14 @@
<div v-if="currentDetail">
<a-input v-model.number="currentDetail.style.left" @blur="blur" />
<a-input v-model.number="currentDetail.style.top" @blur="blur" />
<a-input v-for="(item,index) in keys" :key="index" v-model.number="currentDetail.props[item]" @blur="blur" />
</div>
{{ currentDetail }}--{{ currentIndex }}
</div>
</template>
<script>
import {cloneDeep} from "lodash"
import { cloneDeep } from "lodash";
export default {
data() {
return {
@ -17,12 +18,21 @@ export default {
currentIndex: -1,
};
},
computed: {
keys(){
return this.currentDetail&&Object.keys(this.currentDetail.props)
}
},
created() {
//
this.$event.$on("@editor:publish:activeOne", (item, index) => {
this.currentDetail = cloneDeep(item);
this.currentIndex = index;
});
this.$event.$on("@editor:publish:unActive", (item, index) => {
this.currentDetail = null;
this.currentIndex = -1;
});
//
this.$event.$on("@editor:notice:update", (item, index) => {
//
@ -30,14 +40,18 @@ export default {
this.currentIndex = index;
});
},
beforeDestroy(){
this.$event.$off("@editor:publish:activeOne")
this.$event.$off("@editor:notice:update")
beforeDestroy() {
this.$event.$off("@editor:publish:activeOne");
this.$event.$off("@editor:notice:update");
},
methods: {
blur() {
console.log(this.currentDetail,this.currentIndex);
this.$event.$emit("@editor:publish:updateOne",this.currentDetail,this.currentIndex)
console.log(this.currentDetail, this.currentIndex);
this.$event.$emit(
"@editor:publish:updateOne",
this.currentDetail,
this.currentIndex
);
},
},
};

50
src/ui/editor/MakeLine.vue

@ -42,40 +42,50 @@ export default {
data() {
return {
lineLeft: [],
lineTop: [],
lineTop: [],
lastPos: [],
directionX: 0, // 1 2
directionY: 0, // 1 2
};
},
methods: {
removeAll() {
this.lineLeft = [];
this.lineTop = [];
this.lastPos = [];
this.directionX = 0;
this.directionY = 0;
},
listenerChange(list, index, cb) {
listenerChange(list, index, cb, xifu=true) {
const activeStyle = list[index].style;
const screenWidth = this.$parent.$el.offsetWidth
const screenHeight = this.$parent.$el.offsetHeight
const screenWidth = this.$parent.$el.offsetWidth;
const screenHeight = this.$parent.$el.offsetHeight;
//
if (Math.abs(activeStyle.top) <= value) {
activeStyle.top = 0;
xifu&&(activeStyle.top = 0);
cb && cb(list[index], index);
}
//
if (Math.abs(activeStyle.top+activeStyle.height - screenHeight) <= value) {
activeStyle.top = screenHeight - activeStyle.height;
if (
Math.abs(activeStyle.top + activeStyle.height - screenHeight) <= value
) {
xifu&&(activeStyle.top = screenHeight - activeStyle.height);
cb && cb(list[index], index);
}
//
if (Math.abs(activeStyle.left) <= value) {
activeStyle.left = 0;
xifu&&(activeStyle.left = 0);
cb && cb(list[index], index);
}
//
if (Math.abs(activeStyle.left+activeStyle.width-screenWidth) <= value) {
activeStyle.left = screenWidth - activeStyle.width;
if (
Math.abs(activeStyle.left + activeStyle.width - screenWidth) <= value
) {
xifu&&(activeStyle.left = screenWidth - activeStyle.width);
cb && cb(list[index], index);
}
if (list.length==1) {
return
if (list.length == 1) {
return;
}
list.forEach((item, jndex) => {
if (jndex !== index) {
@ -91,49 +101,49 @@ export default {
// TODO
// --
if (Math.abs(activeStyle.top - curStyle.top) <= value) {
activeStyle.top = curStyle.top;
xifu&&(activeStyle.top = curStyle.top);
this.makeTop2Bottom(curStyle.top);
cb && cb(list[index], index);
}
// --
if (Math.abs(actBottom - curBottom) <= value) {
activeStyle.top = curBottom - activeStyle.height;
xifu&&(activeStyle.top = curBottom - activeStyle.height);
this.makeTop2Bottom(curBottom);
cb && cb(list[index], index);
}
// --
if (Math.abs(activeStyle.top - curBottom) <= value) {
activeStyle.top = curBottom;
xifu&&(activeStyle.top = curBottom);
this.makeTop2Bottom(curBottom);
cb && cb(list[index], index);
}
// --
if (Math.abs(activeStyle.left - curStyle.left) <= value) {
activeStyle.left = curStyle.left;
xifu&&(activeStyle.left = curStyle.left);
this.makeLeft2Right(curStyle.left);
cb && cb(list[index], index);
}
// --
if (Math.abs(activeStyle.left - curRight) <= value) {
activeStyle.left = curRight;
xifu&&(activeStyle.left = curRight);
this.makeLeft2Right(curRight);
cb && cb(list[index], index);
}
// --
if (Math.abs(actRight - curRight) <= value) {
activeStyle.left = curRight - activeStyle.width;
xifu&&(activeStyle.left = curRight - activeStyle.width);
this.makeLeft2Right(curRight);
cb && cb(list[index], index);
}
// --
if (Math.abs(actBottom - curStyle.top) <= value) {
activeStyle.top = curStyle.top - activeStyle.height;
xifu&&(activeStyle.top = curStyle.top - activeStyle.height);
this.makeTop2Bottom(curStyle.top);
cb && cb(list[index], index);
}
// --
if (Math.abs(actRight - curStyle.left) <= value) {
activeStyle.left = curStyle.left - activeStyle.width;
xifu&&(activeStyle.left = curStyle.left - activeStyle.width);
this.makeLeft2Right(curStyle.left);
cb && cb(list[index], index);
}

289
src/ui/editor/Shape.vue

@ -1,12 +1,299 @@
<template>
<div class="shape">
<slot></slot>
<div v-show="index == activeIndex" ondragstart="return false;">
<div
@mousedown="mousedown($event, 1)"
class="shape-circle top-left"
></div>
<div
@mousedown="mousedown($event, 2)"
class="shape-circle top-center"
></div>
<div
@mousedown="mousedown($event, 3)"
class="shape-circle top-right"
></div>
<div
@mousedown="mousedown($event, 4)"
class="shape-circle center-left"
></div>
<div
@mousedown="mousedown($event, 5)"
class="shape-circle center-right"
></div>
<div
@mousedown="mousedown($event, 6)"
class="shape-circle bottom-left"
></div>
<div
@mousedown="mousedown($event, 7)"
class="shape-circle bottom-center"
></div>
<div
@mousedown="mousedown($event, 8)"
class="shape-circle bottom-right"
></div>
</div>
</div>
</template>
<script>
import componentList from "@/data/component-list";
export default {
inject: ["active"],
props: ["index"],
computed: {
activeComponent() {
return this.active ? this.active.comp : null;
},
activeIndex() {
return this.active ? this.active.index : null;
},
},
data() {
return {
isResizing: false,
};
},
created() {},
methods: {
mousedown(ev, type) {
ev.stopPropagation();
this.isResizing = true;
let startX = ev.clientX;
let startY = ev.clientY;
let width = this.activeComponent.style.width;
let owidth = this.activeComponent.origin.width;
let height = this.activeComponent.style.height;
let oheight = this.activeComponent.origin.height;
let left = this.activeComponent.style.left;
let top = this.activeComponent.style.top;
let isEdit = false;
document.onmousemove = (ex) => {
if (type == 1) {
let offsetX =
width - (ex.clientX - startX) < owidth
? width - owidth
: ex.clientX - startX;
let offsetY =
height - (ex.clientY - startY) < oheight
? height - oheight
: ex.clientY - startY;
let w = width - offsetX;
let h = height - offsetY;
let l = left + offsetX;
let t = top + offsetY;
isEdit = true;
this.activeComponent.style = {
width: w,
height: h,
left: l,
top: t,
};
this.$emit("update");
}
if (type == 2) {
// let offsetX = width - (ex.clientX - startX)<owidth?width-owidth:ex.clientX - startX
let offsetY =
height - (ex.clientY - startY) < oheight
? height - oheight
: ex.clientY - startY;
let w = width;
let h = height - offsetY;
let l = left;
let t = top + offsetY;
isEdit = true;
this.activeComponent.style = {
width: w,
height: h,
left: l,
top: t,
};
this.$emit("update");
}
if (type == 3) {
let offsetX =
width + (ex.clientX - startX) < owidth
? owidth - width
: ex.clientX - startX;
let offsetY =
height - (ex.clientY - startY) < oheight
? height - oheight
: ex.clientY - startY;
let w = width + offsetX;
let h = height - offsetY;
let l = left;
let t = top + offsetY;
isEdit = true;
this.activeComponent.style = {
width: w,
height: h,
left: l,
top: t,
};
this.$emit("update");
}
if (type == 4) {
let offsetX =
width - (ex.clientX - startX) < owidth
? width - owidth
: ex.clientX - startX;
let w = width - offsetX;
let h = height;
let l = left + offsetX;
let t = top;
isEdit = true;
this.activeComponent.style = {
width: w,
height: h,
left: l,
top: t,
};
this.$emit("update");
}
if (type == 5) {
let offsetX =
width + (ex.clientX - startX) < owidth
? owidth - width
: ex.clientX - startX;
let w = width + offsetX;
let h = height;
let l = left;
let t = top;
isEdit = true;
this.activeComponent.style = {
width: w,
height: h,
left: l,
top: t,
};
this.$emit("update");
}
if (type == 6) {
let offsetX =
width - (ex.clientX - startX) < owidth
? width - owidth
: ex.clientX - startX;
let offsetY =
height + (ex.clientY - startY) < oheight
? oheight - height
: ex.clientY - startY;
let w = width - offsetX;
let h = height + offsetY;
let l = left + offsetX;
let t = top;
isEdit = true;
this.activeComponent.style = {
width: w,
height: h,
left: l,
top: t,
};
this.$emit("update");
}
if (type == 7) {
// let offsetX = width - (ex.clientX - startX)<owidth?width-owidth:ex.clientX - startX
let offsetY =
height + (ex.clientY - startY) < oheight
? oheight - height
: ex.clientY - startY;
let w = width;
let h = height + offsetY;
let l = left;
let t = top;
isEdit = true;
this.activeComponent.style = {
width: w,
height: h,
left: l,
top: t,
};
this.$emit("update");
}
if (type == 8) {
let offsetX =
width + (ex.clientX - startX) < owidth
? owidth - width
: ex.clientX - startX;
let offsetY =
height + (ex.clientY - startY) < oheight
? oheight - height
: ex.clientY - startY;
let w = width + offsetX;
let h = height + offsetY;
let l = left;
let t = top;
isEdit = true;
this.activeComponent.style = {
width: w,
height: h,
left: l,
top: t,
};
this.$emit("update");
}
};
document.onmouseup = (ex) => {
this.isResizing = false;
document.onmousemove = null;
document.onmouseup = null;
if (isEdit) {
this.$emit("over");
}
};
},
},
};
</script>
<style lang="scss" scoped>
.shape {
position: absolute;
transition: none;
.shape-circle {
position: absolute;
width: 8px;
height: 8px;
border: 1px solid red;
border-radius: 50%;
&.top-left {
left: -4px;
top: -4px;
cursor: ew-resize;
}
&.top-center {
left: 50%;
top: -4px;
transform: translateX(-50%);
cursor: ns-resize;
}
&.top-right {
right: -4px;
top: -4px;
}
&.center-left {
left: -4px;
top: 50%;
transform: translateY(-50%);
}
&.center-right {
right: -4px;
top: 50%;
transform: translateY(-50%);
}
&.bottom-left {
left: -4px;
bottom: -4px;
}
&.bottom-center {
left: 50%;
bottom: -4px;
transform: translateX(-50%);
}
&.bottom-right {
right: -4px;
bottom: -4px;
}
}
&.moving {
z-index: 99;
pointer-events: none;
@ -16,7 +303,7 @@
pointer-events: none;
user-select: none;
}
> .component{
> .component {
width: 100%;
height: 100%;
}

118
src/ui/editor/editor.vue

@ -6,7 +6,10 @@
@dragleave="dragleave"
@dragover="dragover"
@drop="drop"
@mousedown="clearActive"
>
{{ current }}
{{ history.length }}
<Shape
v-for="(item, index) in componentList"
ref="shape"
@ -16,9 +19,17 @@
movingIndex != -1 && movingIndex != index ? 'staying' : '',
]"
:key="index"
@update="update"
@over="over"
:index="index"
@changeSize="changeSize($event, index)"
:style="[$computeStyle(item.style)]"
>
<customComponent :detail="item" :key="index" />
<customComponent
:style="[$computeStyle(item.style, true)]"
:detail="item"
:key="index"
/>
</Shape>
<MakeLine ref="makeline"> </MakeLine>
</div>
@ -31,6 +42,11 @@ import Shape from "./Shape";
import customComponent from "./customComponent";
import MakeLine from "./MakeLine";
export default {
provide() {
return {
active: this.activeComponent,
};
},
components: {
Shape,
customComponent,
@ -41,29 +57,94 @@ export default {
isEnter: false,
movingIndex: -1,
activeIndex: -1,
current: 0,
componentList: [],
history: [],
activeComponent: {
index: -1,
comp: null,
},
};
},
created () {
created() {
//
this.$event.$on("@editor:publish:updateOne",(item,index)=>{
this.$event.$on("@editor:publish:updateOne", (item, index) => {
this.componentList.splice(index, 1, item);
//
//
this.$event.$emit("@editor:notice:update",item,index);
})
this.$refs.makeline.listenerChange(this.componentList, index);
this.$event.$emit("@editor:notice:update", item, index);
});
this.$event.$on("@editor:publish:chexiao", () => {
if (this.current - 1 >= 0) {
//
this.componentList = cloneDeep(this.history[this.current - 1]);
this.current -= 1;
}
});
this.$event.$on("@editor:publish:cz", () => {
if (this.current + 1 < this.history.length) {
//
this.componentList = cloneDeep(this.history[this.current + 1]);
this.current += 1;
}
});
},
beforeDestroy(){
this.$event.$off("@editor:publish:updateOne")
beforeDestroy() {
this.$event.$off("@editor:publish:updateOne");
},
methods: {
update() {
this.$event.$emit(
"@editor:notice:update",
this.componentList[this.activeIndex],
this.activeIndex
);
// this.$refs.makeline.listenerChange(
// this.componentList,
// this.activeIndex,
// (item, index) => {
// this.$event.$emit("@editor:notice:update", item, index);
// },
// true
// );
},
over() {
this.history.push(cloneDeep(this.componentList));
this.current = this.history.length - 1;
},
clearActive() {
this.$refs.makeline.removeAll();
this.activeIndex = -1;
this.$event.$emit("@editor:publish:unActive");
this.activeComponent.comp = null;
this.activeComponent.index = -1;
},
changeSize(sty, index) {
let el = this.componentList[index];
el.style.width = sty.w;
el.style.height = sty.h;
el.style.left = sty.l;
el.style.top = sty.t;
this.componentList.splice(index, 1, el);
//
this.$event.$emit("@editor:notice:update", el, index);
},
mousedown(ev, index) {
ev.stopPropagation();
let startX = ev.clientX;
let startY = ev.clientY;
let startW = this.$refs.shape[index].$el.offsetLeft;
let startH = this.$refs.shape[index].$el.offsetTop;
this.activeIndex = index
this.$event.$emit("@editor:publish:activeOne",this.componentList[index],index);
this.activeIndex = index;
this.activeComponent.comp = this.componentList[index];
this.activeComponent.index = index;
this.$event.$emit(
"@editor:publish:activeOne",
this.componentList[index],
index
);
let isMoving = false;
document.onmousemove = (ex) => {
if (!isMoving && Math.abs(ex.clientX - startX) > 1) {
@ -80,14 +161,22 @@ export default {
el.style.top = offsetY;
this.componentList.splice(index, 1, el);
//
this.$event.$emit("@editor:notice:update",el,index);
this.$refs.makeline.listenerChange(this.componentList, index,(item,index)=>{
this.$event.$emit("@editor:notice:update",item,index);
});
this.$event.$emit("@editor:notice:update", el, index);
this.$refs.makeline.listenerChange(
this.componentList,
index,
(item, index) => {
this.$event.$emit("@editor:notice:update", item, index);
}
);
}
};
document.onmouseup = (ex) => {
//
if (isMoving) {
this.history.push(cloneDeep(this.componentList));
this.current = this.history.length - 1;
}
this.$refs.makeline.removeAll();
isMoving = false;
this.movingIndex = -1;
@ -107,6 +196,7 @@ export default {
drop(ev) {
ev.stopPropagation();
try {
this.clearActive();
this.isEnter = false;
var { id, x, y } = JSON.parse(
decodeURIComponent(ev.dataTransfer.getData("component-transfer"))
@ -117,6 +207,8 @@ export default {
el.style.left = offsetX;
el.style.top = offsetY;
this.componentList.push(el);
this.history.push(cloneDeep(this.componentList));
this.current = this.history.length - 1;
} catch (error) {
console.warn(error);
}

34
src/ui/header/header.vue

@ -1,5 +1,35 @@
<template>
<header>
header
<slot></slot>
<a-button @click="chexiao">撤销</a-button>
<a-button @click="cz">重做</a-button>
</header>
</template>
</template>
<script>
export default {
components: {},
mounted() {
// console.log(subComp._Ctor[0]());
// console.log(subComp.render());
// this.$slots.default = [];
// this.$slots.default.push(subComp.render());
// this.$parent.$forceUpdate()
},
methods: {
cz() {
this.$event.$emit(
"@editor:publish:cz",
// this.currentDetail,
// this.currentIndex
);
},
chexiao() {
this.$event.$emit(
"@editor:publish:chexiao",
// this.currentDetail,
// this.currentIndex
);
},
},
};
</script>

17
src/ui/header/sub.vue

@ -0,0 +1,17 @@
<template>
<div>sub</div>
</template>
<script>
export default {
text: 'sadas',
created () {
console.log('created');
// console.log(this);
// console.log(this.$parent);
// this.$parent.$slots.default = [];
// this.$parent.$slots.default.push(this.$vnode);
this.$parent.$slots = {default: [this.$vnode]}
console.log(this.$vnode);
}
}
</script>

3
src/views/home/index.vue

@ -1,6 +1,7 @@
<template>
<div class="home">
<x-header></x-header>
<x-header>
</x-header>
<div class="layout">
<panel class="panel"></panel>
<editor class="editor"></editor>

Loading…
Cancel
Save