vue 拖动

原创
05/15 15:27
阅读数 23

需求:有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>

 如果拖拽的内容含有图片

<div @dragstart="handleDragStart" class="dialogLeft">
     <div v-for="(item,index) in blockList" :key="index" draggable :data-index="index"
        style="margin-bottom:10px;" class="dialogLeftLi">
          <div style="height:100px;">
              <img :src="item.picUrl" alt="" style="max-width:100%;max-height:100%">
          </div>
          <div>{{item.name}}</div>
     </div>

</div>
    handleDragStart(e) {
      console.log(e.target);
      console.log(e.target.nodeName);
      if (e.target.nodeName == "IMG") {
        e.dataTransfer.setData(
          "index",
          e.target.parentElement.parentElement.dataset.index
        );
      } else {
        e.dataTransfer.setData("index", e.target.dataset.index);
      }   
    },

总结:原理是根据 dragstart拖动组件并传值,drop时获取传过来的值,并把传过来的组件保存起来,根据选中的编辑模板与选中的组件,动态渲染预览界面(编辑模板与预览模板是对应的)

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部