vue拖拽组件draggable

1、安装vuedraggable依赖

npm i vuedraggable

2、在页面中引入

import Draggable from 'vuedraggable'
components: {
  Draggable
},

下面为实图使用,代码直接参考下面的,拷贝即可使用
在这里插入图片描述

//主页面
<template>
  <div class="ctnr">
    <div class="station-area">
      <div class="text-area">
        <el-button v-if="disabledDrag && section.length < 4" type="text" @click="changeAdd">新建
        </el-button>
        <div class="edit-area">
          <el-button v-if="disabledDrag" type="text" @click="changeDrag">编辑
          </el-button>
          <div v-else>
            <el-button type="text" @click="changeDrag('updateList')">完成</el-button>
            <el-button type="text" @click="changeDrag('clearList')">取消</el-button>
          </div>
        </div>
      </div>
    </div>
    <draggable :disabled="disabledDrag" class="box" v-model="section" @start="onStartBlock" @end="onEndBlock"
      animation="300">
      <transition-group>
        <div class="section" v-for="(item,index) in section" :key="index">
          <div class="section-card">
            <h1 class="card-title">
              <el-input class="title-inp" v-if="!disabledDrag" v-model="item.name"></el-input>
              <span v-else>{{item.name}}</span>
              <i v-if="!disabledDrag" class="el-icon-circle-plus i-plus"
                @click="bindAddSuit(item.id,item.suites.length)"></i>
            </h1>
            <draggable :disabled="disabledDrag" class="card-box" v-model="item.suites" @start="onStartSuite(item.id)"
              @end="onEndSuite(item.id)" animation="300">
              <transition-group>
                <div class="item" v-for="(item2,index2) in item.suites" :key="index2">
                  <div class="item-card" :style="'background:'+item2.color" :class="{'href-type':disabledDrag}"
                    @click="goPreview(item2)">
                    <div class="op-box" v-if="!disabledDrag">
                      <i class="el-icon-edit" @click="bindEditSuit(item2,item.id)"></i>
                      <i class="el-icon-delete" @click="bindRemoveSuit(item2.id)"></i>
                    </div>
                    <span class="card-name">{{item2.name}}</span>

                  </div>
                </div>
              </transition-group>
            </draggable>


          </div>
        </div>
      </transition-group>
    </draggable>
    <suit-box ref="SuitBox" @refreshList="refreshList"></suit-box>
  </div>
</template>

<script>
  import Draggable from 'vuedraggable'
  import SuitBox from '@/components/CommonForm/SuitBox'
  export default {
    data() {
      return {
        disabledDrag: true,
        oSection: [],
        section: [],
        isUpdateBlock: false,
        isUpdateSuit: [],
      };
    },

    components: {
      Draggable,
      SuitBox
    },
    watch: {
      section: {
        handler(newVal, oldVal) {
          oldVal.length > 0 && (this.isUpdateBlock = true)
        },
        deep: true
      }
    },

    computed: {},

    mounted() {
      this.getBlockList()
    },

    created() {},

    methods: {
      getBlockList() {
      	var data = [
    {
        "create_time": "2022-04-01 15:12:33",
        "id": 2,
        "modify_time": "2022-06-29 19:44:23",
        "name": "测试区域2133213122355",
        "order_num": 1,
        "suites": [
            {
                "color": "#A47373",
                "create_time": "2022-04-01 17:48:32",
                "fillable": false,
                "id": 4,
                "modify_time": "2022-07-29 17:55:52",
                "name": "日常签到",
                "order_num": 1,
                "template_id": 423
            },
            {
                "color": "#9013FE",
                "create_time": "2022-10-09 11:01:02",
                "fillable": true,
                "id": 22,
                "modify_time": "2022-10-09 11:01:02",
                "name": "接口",
                "order_num": 2,
                "template_id": 369
            }
        ]
    },
    {
        "create_time": "2022-04-01 15:12:41",
        "id": 3,
        "modify_time": "2022-07-29 17:38:01",
        "name": "防冻液防冻液111",
        "order_num": 2,
        "suites": []
    },
    {
        "create_time": "2022-06-28 15:16:56",
        "id": 41,
        "modify_time": "2022-07-27 14:06:52",
        "name": "额3v",
        "order_num": 3,
        "suites": [
            {
                "color": "#F9F115",
                "create_time": "2022-07-27 14:07:02",
                "fillable": false,
                "id": 18,
                "modify_time": "2022-07-27 14:07:02",
                "name": "43关闭",
                "order_num": 1,
                "template_id": 407
            }
        ]
    },
    {
        "create_time": "2022-06-28 15:16:52",
        "id": 36,
        "modify_time": "2022-09-05 11:31:14",
        "name": "供电局",
        "order_num": 4,
        "suites": [
            {
                "color": "#BD10E0",
                "create_time": "2022-07-27 14:08:20",
                "fillable": true,
                "id": 19,
                "modify_time": "2022-07-27 14:08:20",
                "name": "看给客户",
                "order_num": 1,
                "template_id": 369
            }
        ]
    },
    {
        "create_time": "2022-06-28 15:16:56",
        "id": 42,
        "modify_time": "2022-06-29 19:44:23",
        "name": "",
        "order_num": 5,
        "suites": []
    },
    {
        "create_time": "2022-06-28 15:16:52",
        "id": 39,
        "modify_time": "2022-06-29 19:44:23",
        "name": "",
        "order_num": 6,
        "suites": []
    },
    {
        "create_time": "2022-06-28 15:16:56",
        "id": 40,
        "modify_time": "2022-08-25 17:05:46",
        "name": "saca",
        "order_num": 7,
        "suites": [
            {
                "color": "#CB2929",
                "create_time": "2022-08-25 17:05:52",
                "fillable": false,
                "id": 21,
                "modify_time": "2022-08-25 17:05:52",
                "name": "sacas",
                "order_num": 1,
                "template_id": 423
            }
        ]
    },
    {
        "create_time": "2022-06-28 15:16:52",
        "id": 37,
        "modify_time": "2022-06-29 19:44:23",
        "name": "",
        "order_num": 8,
        "suites": []
    },
    {
        "create_time": "2022-04-01 15:12:25",
        "id": 1,
        "modify_time": "2022-06-29 19:44:23",
        "name": "时分为非就不能用鼠标全选",
        "order_num": 9,
        "suites": [
            {
                "color": "#F8E71C",
                "create_time": "2022-04-01 16:35:25",
                "fillable": false,
                "id": 2,
                "modify_time": "2022-04-01 17:59:12",
                "name": "套件2",
                "order_num": 2,
                "template_id": 363
            },
            {
                "color": "#B33434",
                "create_time": "2022-04-01 18:42:04",
                "fillable": true,
                "id": 6,
                "modify_time": "2022-04-01 18:42:04",
                "name": "卡片222",
                "order_num": 2,
                "template_id": 298
            },
            {
                "color": "#DC17DC",
                "create_time": "2022-04-22 14:21:48",
                "fillable": false,
                "id": 10,
                "modify_time": "2022-04-24 18:27:38",
                "name": "vr",
                "order_num": 3,
                "template_id": 372
            }
        ]
    },
    {
        "create_time": "2022-06-28 15:16:56",
        "id": 43,
        "modify_time": "2022-06-29 19:44:23",
        "name": "",
        "order_num": 10,
        "suites": []
    },
    {
        "create_time": "2022-06-28 15:16:52",
        "id": 38,
        "modify_time": "2022-06-29 19:44:23",
        "name": "",
        "order_num": 11,
        "suites": []
    },
    {
        "create_time": "2022-04-01 15:12:48",
        "id": 4,
        "modify_time": "2022-06-29 19:44:23",
        "name": "测试区域4",
        "order_num": 12,
        "suites": [
            {
                "color": "#994545",
                "create_time": "2022-04-02 10:19:00",
                "fillable": true,
                "id": 8,
                "modify_time": "2022-04-02 10:19:00",
                "name": "车控室",
                "order_num": 1,
                "template_id": 350
            }
        ]
    }
]
        this.section = data
          this.oSection = JSON.parse(JSON.stringify(data))
      },
      refreshList() {
        this.getBlockList()
      },
      onStartBlock() {

      },
      onEndBlock(e) {
        console.log(e)
        this.isUpdateBlock = true
      },
      onStartSuite() {

      },
      onEndSuite(blockId) {
        // 对那个块中的卡片进行了挪动
        !this.isUpdateSuit.includes(blockId) && this.isUpdateSuit.push(blockId)
      },
      changeAdd() {
        for (var i = 0; i < 4; i++) {
            let obj = {name: '',order_num: i + 1,station_id: this.station_id}
            blockAdd(obj).then(res => {})
          }
          this.getBlockList();
      },
      changeDrag(type) {
        this.disabledDrag = !this.disabledDrag
        switch (type) {
          case 'clearList':
            this.section = JSON.parse(JSON.stringify(this.oSection))
            break;

          case 'updateList':
            if (this.isUpdateBlock) {
              this.updateBlock()
            }
            if (this.isUpdateSuit.length > 0) {
              this.updateSuit()
            }
            break;
        }
      },
      bindAddSuit(id, orderNum) {
        if (this.isUpdateBlock || this.isUpdateSuit.length > 0) {
          this.$confirm("区域或卡片有更新是否保存后再新建卡片?", "提示", {
            confirmButtonText: "确认",
            cancelButtonText: "取消",
            type: "warning"
          }).then(() => {
            this.isUpdateBlock && this.updateBlock()
            this.isUpdateSuit.length > 0 && this.updateSuit()
            this.$refs.SuitBox.showModal({
              block_id: id,
              order_num: orderNum + 1
            })
          }).catch(() => {
            this.$refs.SuitBox.showModal({
              block_id: id,
              order_num: orderNum + 1
            })
          })
        } else {
          this.$refs.SuitBox.showModal({
            block_id: id,
            order_num: orderNum + 1
          })
        }
      },
      bindEditSuit(info, id) {
        this.$refs.SuitBox.showModal(Object.assign({
          block_id: id
        }, info), 'edit')
      },
      updateBlock() {
        let data = []
        for (const [index, item] of this.section.entries()) {
          const obj = {
            id: item.id,
            name: item.name,
            order_num: index + 1
          }
          data.push(obj)

        }
        blockModify(data).then(res => {
          this.$message.success('区域更新成功')
          this.isUpdateBlock = false
        })
      },
      updateSuit() {
        const data = []
        for (const item of this.isUpdateSuit) {
          const nowBlock = this.section.filter(res => res.id === item)[0]
          for (const [index2, item2] of nowBlock.suites.entries()) {
            const obj = Object.assign(item2, {
              block_id: item,
              order_num: index2 + 1
            })
            delete obj.create_time
            delete obj.modify_time
            data.push(obj)
          }
        }
        suiteUpdate(data).then(res => {
          this.$message.success('卡片更新成功')
          this.isUpdateSuit = []
        })
        console.log(data)
      },
      bindRemoveSuit(id) {
        this.$confirm("是否删除此卡片?", "提示", {
          confirmButtonText: "确认",
          cancelButtonText: "取消",
          type: "warning"
        }).then(() => {
          suiteDelete({
            id
          }).then(res => {
            this.$message.success('卡片删除成功')
            this.getBlockList()

          })
        }).catch(() => {})
      },
      async goPreview(item) {
        if (!this.disabledDrag) return
        const detail = await templateDetail({
          id: item.template_id
        }).then(res => {
          return res.data
        })
        localStorage.previewForm = JSON.stringify(detail.content)
        let url = this.$router.resolve({
          path: `/preview?type=${item.fillable?'fill':''}&template_id=${item.template_id}`
        });
        window.open(url.href, '_blank');
      }
    }
  }

</script>
<style lang='scss' scoped>
  .ctnr {
    height: calc(100vh - 50px);
    background: #f6f7f9;
    margin: -40px -50px;
    padding: 20px 0 20px 20px;
    overflow-y: scroll;
  }

  .station-area {
    padding: 0 20px;
    display: flex;
    align-items: center;

    .text-area {
      display: flex;
      align-items: center;
      margin-left: auto;

      .edit-area {
        margin-left: 15px;
      }
    }
  }

  /deep/ .el-form-item--small.el-form-item {
    margin-bottom: 0 !important;
  }

  .box {
    width: 100%;
    height: 100%;

  }

  .section {
    width: 50%;
    height: 50%;
    display: inline-block;
    padding: 20px 20px 0 0;

    &-card {
      background: #fff;
      border-radius: 14px;
      height: 100%;
      padding: 20px;
      display: flex;
      flex-wrap: wrap;

      // padding: ;
      .card-title {
        font-size: 16px;
        margin: 0;
        position: relative;
        width: 100%;
        color: #606266;

        .title-inp {
          width: 50%;
        }

        .i-plus {
          color: #448ef7;
          position: absolute;
          right: 0;
          cursor: pointer;
          font-size: 25px;
        }
      }

      .card-box {
        width: 100%;
        height: calc(100% - 30px);
      }
    }

    .item {
      width: 33.3%;
      padding: 10px 10px 0 0;
      height: 33.3%;
      display: inline-block;

      &-card {
        width: 100%;
        height: 100%;
        background: #eee;
        border-radius: 11px;
        position: relative;
        display: flex;
        align-items: center;
        justify-content: center;
        user-select: none;

        &.href-type {
          cursor: pointer;
        }

        .op-box {
          position: absolute;
          top: 4px;
          right: 5px;
          color: #fff
        }

        .card-name {
          color: #fff;
          font-size: 16px;
          width: 80%;
          overflow: hidden;
          text-overflow: ellipsis;
          white-space: nowrap;
          text-align: center;
        }
      }

    }
  }

</style>

//组件
<template>
  <div>
    <el-dialog @click.native="bindClosePicker" :title="type==='edit'?'编辑卡片':'添加卡片'" :visible.sync="dialogFormVisible"
      :before-close="bindClose">
      <el-form :model="form" ref="ruleForm" size="small" :rules="rules" class="form-style">
        <el-form-item label="卡片名称" :label-width="formLabelWidth" prop="name">
          <el-input v-model="form.name" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="选择模板" :label-width="formLabelWidth" prop="template_id">
          <el-select v-model="form.template_id" placeholder="请选择">
            <el-option v-for="item in templateData" :key="item.id" :label="item.name" :value="item.id"></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="选择背景色" :label-width="formLabelWidth" prop="color">
          <div class="picker-input" style="position:relative">
            <div @click.stop="bindShowPicker" class="color-tip" :style="'background:'+form.color"></div>
            <el-input v-model="form.color" autocomplete="off">
            </el-input>
          </div>
          <div class="picker-box" v-if="showPicker" tabindex="0" @click.stop="">
            <sketch-picker v-model="pickerColor" @input="updatePickerColor">
            </sketch-picker>
          </div>

        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="bindClose(()=>dialogFormVisible = false)" size="small">取 消</el-button>
        <el-button :loading="postLoading" type="primary" @click="bindPost" size="small">确 定</el-button>
      </div>
    </el-dialog>
    <!-- :disableAlpha="true" -->

  </div>
</template>

<script>
  import {
    Sketch
  } from 'vue-color'
  import {
    suiteUpdate
  } from '@/api/commonForm'
  import {
    listTemplate
  } from '@/api/form/form'
  import {
    number
  } from '@/utils/validate'
  export default {
    data() {
      const validateNumber = (rule, value, callback) => {
        console.log(rule, value, callback)
        if (value && !number(value)) {
          callback(new Error('排序值输入错误'));
        } else {
          callback()
        }
      };
      const validateColor = (rule, value, callback) => {
        console.log(rule, value, callback)
        const reg = /^#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$/
        if (!value) {
          callback(new Error('请选择色值'));
        } else if (value && !reg.test(value)) {
          callback(new Error('色值输入错误'));
        } else {
          callback()
        }
      };
      return {
        pickerColor: '',
        dialogFormVisible: false,
        formLabelWidth: '100px',
        form: {

        },
        type: 'add',
        postLoading: false,
        templateData: [],
        showPicker: false,
        rules: {
          name: [{
            required: true,
            message: '请输入卡片名称',
            trigger: 'blur'
          }],
          template_id: [{
            required: true,
            message: '请选择模板',
            trigger: 'change'
          }],
          color: [{
            required: true,
            validator: validateColor,
            trigger: 'blur'
          }],
          order_num: [{
            validator: validateNumber,
            trigger: 'blur'
          }],
        }
      };
    },

    components: {
      'sketch-picker': Sketch,
    },

    computed: {

    },
    watch: {},
    mounted() {
      this.getListTemplate()
    },

    methods: {
      async showModal(info, type) {
        this.type = type || 'add'
        if (info) {
          const {
            name,
            id,
            template_id,
            order_num,
            block_id,
            color
          } = info
          this.form = {
            name,
            template_id,
            id,
            order_num,
            block_id,
            color: !color ? '' : color
          }
        } else {
          this.form = {}
        }
        this.dialogFormVisible = true
      },
      getListTemplate() {
        listTemplate({
          page: 1,
          page_size: 100000
        }).then(res => {
          this.templateData = res.data
        })
      },
      bindPost() {
        console.log(this.form)
        this.postLoading = true
        this.$refs.ruleForm.validate(async (valid) => {
          if (valid) {
            this.form.order_num && (this.form.order_num = parseInt(this.form.order_num))
            await suiteUpdate([this.form]).then(res => {})
            this.postLoading = false
            this.$message.success(this.type === 'edit' ? '编辑成功' : '添加成功')
            this.bindClose(() => this.dialogFormVisible = false)
            this.$emit('refreshList')

          } else {
            this.postLoading = false
            return false
          }
        });


      },
      bindClose(done) {
        this.pickerColor = ''
        this.$refs.ruleForm.resetFields()
        done()
      },
      bindShowPicker() {
        this.showPicker = true
      },
      bindClosePicker() {
        this.showPicker = false
      },
      updatePickerColor(e) {
        console.log(e)
        this.$set(this.form, 'color', e.hex)
      }
    }
  }

</script>
<style lang='scss' scoped>
  /deep/.dialog-footer {
    text-align: center;

    .el-button {
      width: 120px;
    }

    .el-button+.el-button {
      margin-left: 70px;
    }

  }

  .form-style {
    width: 70%;
    margin: 0 auto;
  }

  /deep/ .el-select {
    width: 100%;
  }

  .permission-ctnr {
    height: 200px;
    overflow-y: scroll;
    border: 1px solid #DCDFE6;
    border-radius: 4px;

  }

  .picker-box {
    position: absolute;
    top: 40px;
    left: -25%;
  }

  /deep/.picker-input {
    .color-tip {
      width: 15px;
      height: 15px;
      position: absolute;
      z-index: 1;
      top: 9px;
      left: 10px;
      border: 1px solid #eeeff2;
      border-radius: 3px;
    }

    .el-input__inner {
      padding-left: 30px;
    }
  }

</style>

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值