【vue2中拖拽组件实现自定义首页】

1.安装插件vuedraggable,在页面中引入
2.背景图片需要替换成自己本地图片

<template>
    <div class='test'>
        <el-button type="primary" style="position: fixed;top: 50px;right: 30px;" @click="watchDrag">保存</el-button>
      <div class="main">
        <draggable v-bind="dragOptions1" class="left" v-model="dataList">
          <div
            :data-width="item.width"
            :data-height="item.height"
            :class="[
              'item',
              'item_width_' + item.width,
              'item_height_' + item.height,
              'item_' + item.component
            ]"
            v-for="(item, index) in dataList"
            :key="index"
          >
            <div class="cover">
              <span>{{ item.title }}{{ item.width }}×{{ item.height }}</span>
            </div>
          </div>
        </draggable>
        <div class="right">
          <draggable v-bind="dragOptions2"  :disabled="false"   class="rightBox" :list="dataList2">
            <div
              :class="[
                'item',
                'item_width_' + item.width,
                'item_height_' + item.height,
              ]"
              v-for="(item, index) in dataList2"
              :key="index"
            >
              <div class="moveDialog">
                <Button type="primary" size="small" class="edit" @click="edit(item)">编 辑</Button>
                <Button type="primary" size="small" class="del" @click="del(item)">删 除</Button>
              </div>
              <!-- style="pointer-events: none;cursor: pointer;" -->
              <components :ref='item.component' :is="item.component" ></components>
            </div>
          </draggable>
        </div>
      </div>
      <el-dialog
        v-model="editModal"
        :visible.sync="editModal"
        class="edit-modal"
        :transfer='false'
        :title="`编辑组件信息`"
        @on-ok="submitFormEdit"
        @on-cancel="handleCancelEdit"
        :mask-closable="false">
          <el-form  ref="formValidate" :model="formValidate" :label-width="100" :rules="ruleValidate">
              <p style="color:gray;font-size:12px;margin:0 0 5px 100px">*(推荐宽度比例:4、8、12、16。)</p>
              <el-form-item  label="宽度比例:" prop="width">
                  <el-input v-model="formValidate.width" placeholder="请输入宽度比例"></el-input>
              </el-form-item>
              <p style="color:gray;font-size:12px;margin:0 0 5px 100px">*(建议高度比例:大于等于当前默认高度。)</p>
              <el-form-item  label="高度比例:" prop="height">
                  <el-input v-model="formValidate.height" placeholder="请输入高度比例"></el-input>
              </el-form-item>
          </el-form>
          <p style="color:red;font-size:12px;">*(提示:以上给出的是较为合适的宽高比例,可酌情调整,不建议暴力调整比例。)</p>
          <div slot="footer" align="right">
              <Button @click="handleCancelEdit">取 消</Button>
              <Button type="primary" @click="submitFormEdit">确 定</Button>
          </div>
      </el-dialog>
      
    </div>
  </template>
  <script>
  import draggable from "vuedraggable";
  import red from "../components/red.vue";
  import orange from "../components/orange.vue";
  import yellow from "../components/yellow.vue";
  import comFour from "../components/comFour.vue";
  import comFive from "../components/comFive.vue";
//   import blue from "./components/blue.vue";
//   import purple from "./components/purper.vue";
//   import pink from "./components/pink.vue";
//   import fff from "./components/fff.vue";
//   import black from "./components/black.vue";
  export default {
   name:'indexEdit',
    components: {
    red,
    orange,
    yellow,
    comFour,
    comFive,
    // blue,
    // purple,
    // pink,
    // fff,
    // black,
    draggable
    },
    data () {
      const widthRule = (rule, value, callback) => {
        if(!value){
          callback(new Error('请输入宽度比例!'))
        }else if(!/^[1-9]([0-9])*$/g.test(value)){
          callback(new Error('只能输入正整数!'))
        }else if(value < 4){
          callback(new Error('宽度比例不能小于4!'))
        }else if(value > 16){
          callback(new Error('宽度比例不能大于16!'))
        }else{
          callback()
        }
      }
      const heightRule = (rule, value, callback) => {
        if(!value){
          callback(new Error('请输入高度比例!'))
        }else if(!/^[1-9]([0-9])*$/g.test(value)){
          callback(new Error('只能输入正整数!'))
        }else{
          callback()
        }
      }
      return {
        // 拖拽总数据
        dataList: [
          {
            chartId: '1',
            title: "红色",
            name: "red",
            width: 11,
            height: 2,
            component: "red",
          },
          {
            chartId: '2',
            title: "橙色",
            name: "orange",
            width: 5,
            height: 2,
            component: "orange",
          },
          {
            chartId: '3',
            title: "黄色",
            name: "yellow",
            width: 11,
            height: 2,
            component: "yellow",
          },
          {
            chartId: '4',
            title: "绿色",
            name: "comFour",
            width: 5,
            height: 2,
            component: "comFour",
          },
          {
            chartId: '5',
            title: "青色",
            name: "comFive",
            width: 16,
            height: 2,
            component: "comFive",
          },
          {
            chartId: '6',
            title: "蓝色",
            name: "blue",
            width: 4,
            height: 3,
            component: "blue",
          },
          {
            chartId: '7',
            title: "紫色",
            name: "purple",
            width: 8,
            height: 3,
            component: "purple",
          },
          {
            chartId: '8',
            title: "粉色",
            name: "pink",
            width: 4,
            height: 3,
            component: "pink",
          },
          {
            chartId: '9',
            title: "白色",
            name: "fff",
            width: 12,
            height: 3,
            component: "fff",
          },
          {
            chartId: '10',
            title: "黑色",
            name: "black",
            width: 4,
            height: 3,
            component: "black",
          }
        ],
        // 生成页面数据 
        dataList2: [],
        droplist: [],
        // 编辑弹窗
        editModal: false,
        // 编辑表单
        formValidate: {
          width: 4,
          height: 1
        },
        // 编辑表单限制
        ruleValidate: {
          width: [
            { required: true, validator: widthRule }
          ],
          height: [
            { required: true, validator: heightRule }
          ]
        }
       }
    },
    computed: {
      dragOptions1() {
        console.log(this.dataList2,this.dataList,'-----2222')
        return {
            animation: 300,
            group: {
                name:'group',//名称相同的分组可以相互拖拽
                pull:true, //是否允许拖出当前组
                put:true //是否允许拖入当前组
            },
            chosenClass: "sortable-btn",
            forceFallback: true,
            handle: ".item" // 只有按住拖动手柄才能使列表单元进行拖动
        }
      },
      dragOptions2() {
        console.log(this.dataList2,this.dataList,'-----')
        return {
          animation: 300,
          group: {
            name:'group',
            pull:false,
            put:true
          },
          ghostClass: 'ghost',
          forceFallback: true,
          handle: ".moveDialog"
        }
      }
    },
    mounted() {},
    methods: {
      watchDrag() {
        let arr = [
        {
            chartId: '1',
            title: "红色",
            name: "red",
            width: 4,
            height: 2,
            component: "red",
          },
          {
            chartId: '2',
            title: "橙色",
            name: "orange",
            width: 12,
            height: 2,
            component: "orange",
          },
          {
            chartId: '3',
            title: "黄色",
            name: "yellow",
            width: 16,
            height: 1,
            component: "yellow",
          },
        ]
        this.dataList2 = arr
        console.log(this.dataList2,this.dataList,'11-----')
      },
      // 编辑按钮
      edit(row) {
        console.log(row,"-----")
          this.editModal = true
          this.formValidate = JSON.parse(JSON.stringify(row))
      },
      // 删除按钮
      del(data){
        let dataList2 = JSON.parse(JSON.stringify(this.dataList2))
        this.dataList2 = dataList2.filter(item => item.chartId !== data.chartId)
        this.dataList.push(data)
      },
      // 编辑弹窗确定按钮
      submitFormEdit: function () {
        this.$refs['formValidate'].validate((valid) => {
          if (valid) {
            this.dataList2.map(item => {
              if(item.chartId === this.formValidate.chartId){
                item.width = this.formValidate.width
                item.height = this.formValidate.height
              }
              return item
            })
            this.handleCancelEdit()
            this.$Message.success('编辑成功!')
          } else {
            console.log('检验不通过!');
          }
        })
      },
      // 编辑弹窗取消按钮
      handleCancelEdit() {
        this.editModal = false
        this.$refs.formValidate.resetFields()
        this.formValidate = {
          width: 4,
          height: 1
        }
      }
    }
  }
  </script>
  <style lang='scss' scoped>
     .test{
      height: calc( 100vh - 84px);
      position: relative;
      .main{
        height: 100%;
        position: relative;
        padding-left: 300px;
          .left{
            position: absolute;
            left: 0;
            float: left;
            width: 300px;
            height: 100%;
            background-color: rgb(238, 238, 240);
            overflow-y: auto;
            overflow-x: hidden;
            padding: 10px;
            .item{
              position: relative;
              height: 180px;
              margin-bottom: 10px;
              white-space: nowrap;
              cursor: pointer;
              background: rgb(239, 243, 247);
              border: 1px solid #DCDFE6;
              border-color: #DCDFE6;
              color: #606266;
              outline: none;
              padding: 12px 20px;
              font-size: 14px;
              border-radius: 4px;
              .cover{
                position: absolute;
                top:0;
                left: 0;
                height: 100%;
                transition: all .2s;
                width: 100%;
                text-align: center;
                background-color: #0006;
                opacity: 0;
                span{
                  line-height: 180px;
                  color:#fff;
                  font-size: 16px;
                }
              }
              &:hover{
                .cover{
                  opacity: 1;
                }
              }
            }
            .sortable-btn{
              box-shadow: 0 0 4px 4px #9992;
            }
            .item_red{
              background: url(../../../assets/images/index/conBg.png);
              background-size: 100% 100%;
              background-repeat: no-repeat;
            }
            .item_orange{
              background: url(../../../assets/images/index/icon12.png);
              background-size: 100% 100%;
              background-repeat: no-repeat;
            }
            .item_yellow{
              background: url(../../../assets/images/index/icon38.png);
              background-size: 100% 100%;
              background-repeat: no-repeat;
            }
            .item_comFour{
              background: url(../../../assets/images/index/icon37.png);
              background-size: 100% 100%;
              background-repeat: no-repeat;
            }
            .item_comFive{
              background: url(../../../assets/images/index/icon35.png);
              background-size: 100% 100%;
              background-repeat: no-repeat;
            }
            // .item_blue{
            //   background: url(../../assets/images/blue.png);
            //   background-size: 100% 100%;
            //   background-repeat: no-repeat;
            // }
            // .item_purple{
            //   background: url(../../assets/images/purper.png);
            //   background-size: 100% 100%;
            //   background-repeat: no-repeat;
            // }
            // .item_pink{
            //   background: url(../../assets/images/pink.png);
            //   background-size: 100% 100%;
            //   background-repeat: no-repeat;
            // }
            // .item_fff{
            //   background: url(../../assets/images/fff.png);
            //   background-size: 100% 100%;
            //   background-repeat: no-repeat;
            // }
            // .item_black{
            //   background: url(../../assets/images/black.png);
            //   background-size: 100% 100%;
            //   background-repeat: no-repeat;
            // }
          }
          .right{
            position: relative;
            height:calc( 100vh - 80px);
            overflow: auto;
            overflow-y: hidden;
            background-color: rgb(239, 243, 247,0.5);
            .rightBox{
              position: relative;
              height: 100%;
              overflow-y: hidden;
              display: grid;
              grid-template-columns: repeat(16, 1fr);
              grid-auto-rows:14vh; 
              grid-auto-flow: row dense;
              gap: 5px 10px;
              padding: 5px;
              // min-height: 650px;
              padding-bottom: 20px;
              .ghost{
                opacity: .7;
                span{
                  display: none;
                }
                &::before{
                  content: "";
                  position: absolute;
                  top:0;
                  left: 0;
                  padding: 8px;
                  cursor: pointer;
                  // background-color: red;
                }
                &::after{
                  content: "(^_^)~";
                  position: absolute;
                  top: 50%;
                  left: 50%;
                  transform: translate(-50%, -50%);
                }
              }
              .item{
                position: relative;
                // background-color: #fff;
                // border-radius: 4px;
                // box-shadow: 0 0 2px 2px #9991;
                .edit{
                  display: none;
                  position: absolute;
                  top: 10px;
                  right: 75px;
                  line-height: 20px;
                  cursor: pointer;
                }
                .del{
                  display: none;
                  position: absolute;
                  top: 10px;
                  right: 10px;
                  line-height: 20px;
                  cursor: pointer;
                }
                .moveDialog{
                  position: absolute;
                  top: 0;
                  left: 0;
                  width: 100%;
                  height: 100%;
                  opacity: 0;
                  background-color: gray;
                  z-index: 999;
                }
                .contentBox{
                  pointer-events: none;
                  cursor: default;
                }
              }
              .item:hover{
                .edit{
                  display: block;
                  opacity: 1;
                }
                .del{
                  display: block;
                  opacity: 1;
                }
                .moveDialog{
                  opacity: 0.9;
                }
              }
              .item_width_1{
                  grid-column-start: span 1;
                  width: 100%;
              }
              .item_width_2{
                  grid-column-start: span 2;
                  width: 100%;
              }
              .item_width_3{
                  grid-column-start: span 3;
                  width: 100%;
              }
              .item_width_4{
                  grid-column-start: span 4;
                  width: 100%;
              }
              .item_width_5{
                  grid-column-start: span 5;
                  width: 100%;
              }
              .item_width_6{
                  grid-column-start: span 6;
                  width: 100%;
              }
              .item_width_7{
                  grid-column-start: span 7;
                  width: 100%;
              }
              .item_width_8{
                  grid-column-start: span 8;
                  width: 100%;
              }
              .item_width_9{
                  grid-column-start: span 9;
                  width: 100%;
              }
              .item_width_10{
                  grid-column-start: span 10;
                  width: 100%;
              }
              .item_width_11{
                  grid-column-start: span 11;
                  width: 100%;
              }
              .item_width_12{
                  grid-column-start: span 12;
                  width: 100%;
              }
              .item_width_13{
                  grid-column-start: span 13;
                  width: 100%;
              }
              .item_width_14{
                  grid-column-start: span 14;
                  width: 100%;
              }
              .item_width_15{
                  grid-column-start: span 15;
                  width: 100%;
              }
              .item_width_16{
                  grid-column-start: span 16;
                  width: 100%;
              }
              .item_height_1{
                  grid-row-start: span 1;
                  // line-height: 100px;
              }
              .item_height_2{
                  grid-row-start: span 2;
                  // line-height: 200px;
              }
              .item_height_3{
                  grid-row-start: span 3;
                  // line-height: 300px;
              }
              .item_height_4{
                  grid-row-start: span 4;
                  // line-height: 400px;
              }
              .item_height_5{
                  grid-row-start: span 5;
                  // line-height: 400px;
              }
              .item_height_6{
                  grid-row-start: span 6;
                  // line-height: 400px;
              }
              .item_height_7{
                  grid-row-start: span 7;
                  // line-height: 400px;
              }
              .item_height_8{
                  grid-row-start: span 8;
                  // line-height: 400px;
              }
              .item_height_9{
                  grid-row-start: span 9;
                  // line-height: 400px;
              }
              .item_height_10{
                  grid-row-start: span 10;
                  // line-height: 400px;
              }
              .item_height_11{
                  grid-row-start: span 11;
                  // line-height: 400px;
              }
              .item_height_12{
                  grid-row-start: span 12;
                  // line-height: 400px;
              }
              .item_height_13{
                  grid-row-start: span 13;
                  // line-height: 400px;
              }
              .item_height_14{
                  grid-row-start: span 14;
                  // line-height: 400px;
              }
              .item_height_15{
                  grid-row-start: span 15;
                  // line-height: 400px;
              }
              .item_height_16{
                  grid-row-start: span 16;
                  // line-height: 400px;
              }
            }
          }
        }
      }
    </style>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值