需求:有2个模板,可以切换模板,组件拖动到一个模板中并预览页面,左边是组件列表,右边是可选择的模板
需要有几个vue 页面
1、home.vue
<template>
<div class="container">
<div @dragstart="handleDragStart" style="float:left;">
<div v-for="(item,index) in componentList" :key="index" draggable :data-index="index">
<i class="fa fa fa-bar-chart"></i>
<span>{{item.label}}</span>
</div>
</div>
<div style="margin-left:150px;">
<div class="template">
选择模板
<el-button @click="selectTemplate(1)">模板1</el-button>
<el-button @click="selectTemplate(2)">模板2</el-button>
</div>
<component v-if="currentEditeTemplate" :is="currentEditeTemplate" :currentTemplate="currentTemplate" :componentList="componentList"></component>
<div v-else style="height:200px;border:1px solid #ccc;">未选择模板</div>
</div>
</div>
</template>
<script>
export default {
name: "home",
data() {
return {
currentTemplate:"",
currentEditeTemplate:"",
newCom: {},
componentList: [
{
component: "v-button",
label: "按钮",
propValue: "按钮",
icon: "el-icon-edit",
animations: [],
events: {},
style: {
// width: "100px",
// height: "100px",
fontSize: 14,
background: "red",
fontWeight: 500,
lineHeight: "",
letterSpacing: 0,
textAlign: "",
color: ""
}
},
{
component: "v-small-button",
label: "小型按钮",
propValue: "小型按钮",
icon: "el-phone",
animations: [],
events: {},
style: {
// width: "50px",
// height: "50px",
fontSize: 14,
background: "green",
fontWeight: 500,
lineHeight: "",
letterSpacing: 0,
textAlign: "",
color: ""
}
}
]
};
},
methods: {
selectTemplate(val){
if(val ==1){
this.currentTemplate = "1"
this.currentEditeTemplate = ()=>import("./EditeTemplate1")
}else{
this.currentTemplate = "2"
this.currentEditeTemplate = ()=>import("./EditeTemplate2")
}
},
handleDragStart(e) {
e.dataTransfer.setData("index", e.target.dataset.index);
console.log(e.target.dataset.index);
}
}
};
</script>
2、2个模板编辑页面 EditeTemplate1.vue 与 EditeTemplate2.vue
<template>
<div class="container">
<div class="editeArea">
编辑模板1
<div
@drop="handleDrop"
@dragover="handleDragover"
@click="deselectCurComponent"
style="border:1px solid red;margin-top:20px;height:150px;"
>
<div>
<el-button @click="delTopCom">删除</el-button>
</div>
<component :is="componentData.top.component" :propValue="componentData.top.propValue"></component>
</div>
<div
@drop="handleDrop1"
@dragover="handleDragover1"
@click="deselectCurComponent1"
style="border:1px solid green;margin-top:20px;height:150px;"
>
<div>
<el-button @click="delTopComBottom">删除</el-button>
</div>
<component :is="componentData.bottom.component" :propValue="componentData.bottom.propValue"></component>
</div>
<el-button @click="saveTemplateData">保存模板</el-button>
<el-button @click="previewPage">预览</el-button>
</div>
</div>
</template>
<script>
import VButton from "@/components/VButton.vue";
import VSmallButton from "@/components/VSmallButton.vue";
export default {
name: "home",
props:{currentTemplate:String,componentList:Array},
components: { VButton, VSmallButton },
data() {
return {
newCom: {},
componentData: {
top: {},
bottom: {}
}
};
},
methods: {
saveTemplateData() {
// let templateData = {
// componentData1: this.componentData,
// otherComponentData1: this.otherComponentData
// };
// this.$set(this.newCom, "componentData1", templateData.componentData1);
// this.newCom = Object.assign({}, this.newCom, templateData);
},
// handleDragStart(e) {
// e.dataTransfer.setData("index", e.target.dataset.index);
// console.log(e.target.dataset.index);
// },
handleDrop(e) {
console.log("drop");
e.preventDefault();
e.stopPropagation();
this.componentData.top = this.componentList[
e.dataTransfer.getData("index")
];
},
handleDragover(e) {
console.log("handleDragover");
event.preventDefault(); // 如果不写,不会触发drop事件
},
deselectCurComponent() {
console.log("click");
},
// 下面的放置区域
handleDrop1(e) {
console.log("drop111");
e.preventDefault();
e.stopPropagation();
this.componentData.bottom = this.componentList[
e.dataTransfer.getData("index")
];
},
handleDragover1(e) {
console.log("handleDragover111");
event.preventDefault(); // 如果不写,不会触发drop事件
},
deselectCurComponent1() {
console.log("click");
},
delTopCom() {
this.componentData.top = {};
},
delTopComBottom() {
this.componentData.bottom = {};
},
previewPage() {
alert("preview");
sessionStorage.setItem("componentData",JSON.stringify(this.componentData))
let currentMenuVideo = this.currentMenuVideo;
//在新窗口中打开
const { href } = this.$router.resolve({
path: "/preview",
query:{currentTemplate:this.currentTemplate}
});
window.open(href, "_blank");
}
}
};
</script>
3、preview.vue
<template>
<div>
<component :is="currentTemplate" :componentData="componentData"></component>
</div>
</template>
<script>
// import Edit from "@/components/Edit.vue";
// import VButton from "@/components/VButton.vue";
// import VSmallButton from "@/components/VSmallButton.vue";
export default {
name: "home",
// components: { VButton, VSmallButton},
data() {
return {
currentTemplate:null,
newCom: {},
componentData: {}
};
},
mounted(){
let componentData = JSON.parse(sessionStorage.getItem("componentData"))
this.componentData = componentData
let currentTemplate = this.$route.query.currentTemplate
this.currentTemplate = ()=>import(`./previewTemplate${currentTemplate}.vue`)
},
methods: {
saveTemplateData() {
// let templateData = {
// componentData1: this.componentData,
// otherComponentData1: this.otherComponentData
// };
// this.$set(this.newCom, "componentData1", templateData.componentData1);
// this.newCom = Object.assign({}, this.newCom, templateData);
}
}
};
</script>
4、预览模板previewTemplate1.vue与previewTemplate1.vue
<template>
<div>
<div
style="border:1px solid red;margin-top:20px;height:150px;"
>
<component :is="componentData.top.component" :propValue="componentData.top.propValue"></component>
</div>
<div
style="border:1px solid green;margin-top:20px;height:150px;"
>
<component :is="componentData.bottom.component" :propValue="componentData.bottom.propValue"></component>
</div>
</div>
</template>
<script>
// import Edit from "@/components/Edit.vue";
import VButton from "@/components/VButton.vue";
import VSmallButton from "@/components/VSmallButton.vue";
export default {
name: "home",
props:{componentData:Object},
components: { VButton, VSmallButton},
data() {
return {
// newCom: {},
// otherComponentData: []
};
},
mounted(){
},
methods: {
}
};
</script>
总结:原理是根据 dragstart拖动组件并传值,drop时获取传过来的值,并把传过来的组件保存起来,根据选中的编辑模板与选中的组件,动态渲染预览界面(编辑模板与预览模板是对应的)