原生draggleable属性实现拖拽功能

本文详细介绍了在Vue.js中实现拖拽功能的实现过程,包括为dragover事件的目标元素添加id或groupName属性以判断拖放合法性,以及通过mousedown事件获取拖拽元素信息。在拖拽结束后,通过handleDragEnd方法处理元素移动,判断元素是否在同一组并进行相应操作。示例代码展示了如何在modelData数据结构中进行增删改查,确保拖拽后的数据正确更新。
摘要由CSDN通过智能技术生成

 给dragover事件的target盒子都绑定一个id或groupName属性,便于判断元素是否可以拖拽到那个位置

<UxCard class="ux-page-modelSet__container flex-column" inner>
          <div :class="['model-set-container-box', isView ? 'model-set-container-box-view' : '']">
            <template v-for="(item, index) in modelData">
              <div
                  :key="index"
                  class="group-title"
                  @click="handleChangeIndex(index)"
                  :class="{'different': index === activeIndex && !isView }"
              >
                <span>{{item.groupName + `(${item.attr.length})`}}</span>
                <div class="opt" v-if="!isView">
                  <Tooltip
                      placement="top"
                      content="编辑"
                      transfer
                  >
                    <i class="simo icon-edit" :class="[item.edit ? '' : 'disable']" @click="handleEditTemplate('edit', index, $event, item)"></i>
                  </Tooltip>
                  <Tooltip
                      placement="top"
                      content="删除"
                      transfer
                  >
                    <i class="simo icon-del" :class="[item.cutable && item.edit ? '' : 'disable']" @click="handleDelTemplate(index, item, $event)"></i>
                  </Tooltip>
                  <Tooltip
                      placement="top"
                      content="上移"
                      transfer
                  >
                    <i class="simo icon-move-up" :class="[index === 0 || !item.edit ? 'disable' : '']" @click="handleUpTemplate(index, $event, index === 0 || !item.edit)"></i>
                  </Tooltip>
                  <Tooltip
                      placement="top"
                      content="下移"
                      transfer
                  >
                    <i class="simo icon-move-down" :class="[index === modelData.length - 1 || !item.edit ? 'disable' : '']" @click="handleDownTemplate(index, $event, index === modelData.length - 1 || !item.edit)"></i>
                  </Tooltip>
                </div>
              </div>
              <div class="card-box"
                   @dragover="handleDragEnd"
                   :groupName="modelData[index].groupName"
              >
                <div class="card-content" v-if="!item.attr.length" :groupName="modelData[index].groupName">
                  <div class="card-empty" :groupName="modelData[index].groupName">
                    <div class="name-empty" :groupName="modelData[index].groupName">
                      新分组至少添加一个属性!
                    </div>
                  </div>
                </div>
                <div class="card-content"
                     v-else
                     v-for="(attr, i) in item.attr"
                     :key="attr.id"
                     :draggable="!!attr.edit"
                     @mousedown="handleMouseDown(attr)"
                     :attrId="attr.id"
                >
                  <div class="card" :attrId="attr.id" :class="{'curser' : !attr.edit}">
                    <div :attrId="attr.id" class="opt" v-if="attr.edit && !isView" @click="handleDelAttribute(index, i, attr)">×</div>
                    <div :attrId="attr.id" class="name">
                      <span :attrId="attr.id" v-if="attr.fieldDefinition.attr==='REQUIRED'">*</span>
                      {{ attr.fieldName }}
                    </div>
                    <div :attrId="attr.id" class="type" v-if="typeMap[attr.fieldType]">{{ typeMap[attr.fieldType][attr.fieldDefinition.format] }}</div>
                  </div>
                </div>
              </div>
            </template>
            <span class="add" @click="handleEditTemplate('add', null, $event)" v-if="!isView">+添加新分组</span>
          </div>
          <template #bottom v-if="!isView">
            <Button @click="handleSave">确认</Button>
            <Button cancel  @click="handleCancle">取消</Button>
          </template>
        </UxCard>

 用mousedown事件来获取要拖拽的盒子信息:

handleMouseDown(w) {
      this.dragItem = w
    },

处理拖拽结束事件,注意需阻止浏览器的默认事件:

handleDragEnd(evt) {
      if (this.isView){
        return
      }
      if (evt.target.attributes.attrid) {
        let fultureId = evt.target.attributes.attrid.nodeValue
        if (this.dragItem.id === fultureId) {
          return
        }
        let futureMsg = []
        this.modelData.forEach((item, i) => {
          item.attr.forEach((attr, index) => {
            if (attr.id === fultureId && attr.edit) {
              futureMsg = [i, index]
            }
          })
        })
        if (!futureMsg.length) {
          return
        }
        let judgeIndex = this.judgeIndex(this.dragItem.id, fultureId)
        if (judgeIndex === 'notCommon') {
          this.modelData[futureMsg[0]].attr.splice(futureMsg[1], 0,this.dragItem)
          this.modelData.forEach((item, index) => {
            item.attr.forEach((attr, i) => {
              if(attr.id === this.dragItem.id && index !== futureMsg[0]) {
                this.modelData[index].attr.splice(i, 1)
              }
            })
          })
        } else {
          this.modelData.forEach((item, index) => {
            item.attr.forEach((attr, i) => {
              // 先把原来的删除
              if(attr.id === this.dragItem.id) {
                this.modelData[index].attr.splice(i, 1)
              }
            })
          })
          // 判断一下要删的在前面还是后面,吧要加的加进去
          if(judgeIndex[0] > judgeIndex[1]){
            this.modelData[futureMsg[0]].attr.splice(futureMsg[1], 0,this.dragItem)
          } else {
            this.modelData[futureMsg[0]].attr.splice(futureMsg[1] - 1, 0,this.dragItem)
          }
        }

      }
      if (evt.target.attributes.groupname) {
        let groupName = evt.target.attributes.groupname.nodeValue
        this.modelData.forEach((item, index) => {
          item.attr.forEach((attr, i) => {
            if(attr.id === this.dragItem.id) {
              this.modelData[index].attr.splice(i, 1)
            }
          })
        })
        this.modelData.forEach((item, index) => {
          if(item.groupName === groupName) {
            this.modelData[index].attr.push(this.dragItem)
          }
        })
      }
      evt.preventDefault();
    },

 判断要移动的属性和将要移到的那个位置的属性是否是同一组:

// 判断两个属性是否在同一组,并且如果在同一组,哪个后面
    judgeIndex(sourceId, targetId) {
      let sourceTemplateIndex = -1
      let targetTemplateIndex = -1
      let sourceAttrIndex = -1
      let targetAttrIndex = -1
      this.modelData.forEach((item, i) => {
        item.attr.forEach((attr, index) => {
          if (attr.id === sourceId) {
            sourceTemplateIndex = i
            sourceAttrIndex = index
          }
          if (attr.id === targetId) {
            targetTemplateIndex = i
            targetAttrIndex = index
          }
        })
      })
      // 如果是在同一个组,返回同一个组
      if (sourceTemplateIndex === targetTemplateIndex) {
        return [sourceAttrIndex, targetAttrIndex]
      } else {
        return 'notCommon'
      }
    },

 modelData:

​
"groupDef": [
        {
            "groupName": "基础属性",
            "edit": false,
            "cutable": false,
            "attr": [
                {
                    "id": "202008250000000000000000000000634",
                    "fieldKey": "name",
                    "location": 0,
                    "edit": false,
                    "cutable": false,
                    "fieldDefinition": {
                        "default": "", 
                        "min": "", 
                        "max": "20", 
                        "format": "single", 
                        "attr": "REQUIRED"
                    },
                    "fieldType": "Text",
                    "fieldName": "配置项名称2"
                },
                {
                    "id": "202008250000000000000000000000636",
                    "fieldKey": "name",
                    "location": 0,
                    "edit": false,
                    "cutable": false,
                    "fieldDefinition": {
                        "default": "", 
                        "min": "", 
                        "max": "20", 
                        "format": "single", 
                        "attr": "REQUIRED"
                    },
                    "fieldType": "Text",
                    "fieldName": "配置项名称1"
                }
            ]
        }, 
        {
            "groupName": "基础属性qqqq",
            "edit": false,
            "cutable": false,
            "attr": [
             {
                "id": "20200825000000000000000000000063qq",
                "fieldKey": "name",
                "location": 0,
                "edit": false,
                "cutable": false,
                "fieldDefinition": {
                    "default": "", 
                    "min": "", 
                    "max": "20", 
                    "format": "single", 
                    "attr": "REQUIRED"
            },
            "fieldType": "Text",
            "fieldName": "配置项名称4"
             },
             {
                "id": "2020082500000000000000000000006333",
                "fieldKey": "name",
                "location": 0,
                "edit": false,
                "cutable": false,
                "fieldDefinition": {
                    "default": "", 
                    "min": "", 
                    "max": "20", 
                    "format": "single", 
                    "attr": "REQUIRED"
                 },
                "fieldType": "Text",
                "fieldName": "配置项名称5"
            }
        ]
    }
]

​

效果图:

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值