美文网首页vue
vue3拖拽demo

vue3拖拽demo

作者: 谢炳南 | 来源:发表于2022-03-07 16:43 被阅读0次

    vue3使用vue-draggable会有如下bug


    微信截图_20220307110305.png
    bace7f2a18d74201980a7fe9368ad135.png

    vue3要安装vue-draggable-next

    npm install vue-draggable-next --save
    

    代码

    <template>
      <div>
        <div class="left-board">
          <el-scrollbar class="left-scrollbar">
            <div class="components-list">
              <div v-for="(item, listIndex) in comList" :key="listIndex">
                <div class="components-title">
                  <svg-icon icon-class="component" />
                  {{ item.title }}
                </div>
                <draggable
                  class="components-draggable"
                  draggable=".components-item"
                  :sort="false"
                  :list="item.list"
                  :clone="cloneComponent"
                  :group="{ name: 'componentsGroup', pull: 'clone', put: false }"
                  @end="onEnd"
                >
                  <div class="components-item" v-for="(element, index) in item.list" :key="index">
                    <div class="components-body">
                      <i class="el-icon-edit"></i>
                      {{ element.label }}
                    </div>
                  </div>
                </draggable>
              </div>
            </div>
          </el-scrollbar>
        </div>
    
        <div class="center-board">
            <el-scrollbar>
              <el-form 
                label-width="120px"
              >
                <div class="center-scrollbar">
                  <draggable class="drawing-board" :list="drawingList.list" :animation="340" group="componentsGroup">
                    <div v-for="(item,index) in drawingList.list" :key="index" class="drawing-item">
                      <el-form-item :label="item.label">
                        <template v-if="item.tagIcon == 'input'">
                          <el-input></el-input>
                        </template>
                        <template v-if="item.tagIcon == 'textarea'">
                          <el-input type="textarea"></el-input>
                        </template>
                        <template v-if="item.tagIcon == 'password'">
                          <el-input type="password"></el-input>
                        </template>
                        <template v-if="item.tagIcon == 'switch'">
                          <el-switch />
                        </template>
                      </el-form-item>
                      <el-icon @click="delHandler(index)" class="drawing-item-delete"><delete /></el-icon>
                    </div>
                  </draggable>
                </div>
              </el-form>
            </el-scrollbar>
        </div>
      </div>
    </template>
    
    <script lang="ts">
    import { defineComponent, reactive } from 'vue';
    import { VueDraggableNext } from 'vue-draggable-next';
    import { Delete } from '@element-plus/icons-vue';
    export default defineComponent({
      components: {
        draggable: VueDraggableNext,
        delete: Delete,
      },
      setup() {
        let tempActiveData:any;
        const comList:any = [
          {
            title: '输入型组件',
            list: [
              {
                label: '单行文本',
                tagIcon: 'input',
              },
              {
                label: '多行文本',
                tagIcon: 'textarea',
              },
              {
                label: '密码',
                tagIcon: 'password',
              },
            ],
          },
          {
            title: '选择型组件',
            list: [],
          },
          {
            title: '布局型组件',
            list: [],
          },
        ];
        const drawingList: any = reactive({
          list: [
            {
              label: '单行文本',
              tagIcon: 'input',
            },
            {
              label: '多行文本',
              tagIcon: 'textarea',
            },
            {
              label: '密码',
              tagIcon: 'password',
            },
            {
              label: '开关',
              tagIcon: 'switch',
            }
          ]
        });
        // 拖动结束
        const onEnd = (obj: any) => {
          if (obj.from != obj.to) {
            drawingList.list.splice(obj.newIndex, 0,tempActiveData);
          }
        };
        // 获取当前拖动的对象
        const cloneComponent = (item:any) => {
          tempActiveData = item;
        };
        // 删除元素
        const delHandler = (index: number) => {
          drawingList.list.splice(index,1);
        };
        return {
          comList,
          drawingList,
          onEnd,
          cloneComponent,
          delHandler,
        };
      },
    })
    </script>
    <style lang="less" scoped>
      .left-board {
        width: 260px;
        position: absolute;
        left: 0;
        top: 0;
        height: 100vh;
        .components-title {
          font-size: 14px;
          color: #222;
          margin: 6px 2px;
        }
        .components-item {
          display: inline-block;
          width: 48%;
          margin: 1%;
          // 限制拖动过去又来回的动画
          transition: transform 0ms !important;
          .components-body {
            padding: 8px 10px;
            background: #f6f7ff;
            font-size: 12px;
            cursor: move;
            border: 1px dashed #f6f7ff;
            border-radius: 3px;
          }
        }
      }
      .center-board {
        height: 100vh;
        width: auto;
        margin: 0 350px 0 260px;
        border-left: 1px solid #f1e8e8;
        border-right: 1px solid #f1e8e8;
        .center-scrollbar {
          padding: 12px 12px 15px 12px;
        }
        .drawing-item {
          padding: 10px 7.5px;
          position: relative;
          cursor: move;
          margin-bottom: 15px;
          &.active{
            background: #f6f7ff;
          }
        }
        .drawing-item-delete {
          right: 24px;
          border-color: #F56C6C;
          color: #F56C6C;
          background: #fff;
          position: absolute;
          top: -10px;
          width: 22px;
          height: 22px;
          line-height: 22px;
          text-align: center;
          border-radius: 50%;
          font-size: 12px;
          border: 1px solid;
          cursor: pointer;
          z-index: 1;
        }
        .drawing-board{
          height: 100%;
          position: relative;
          .sortable-ghost {
            position: relative;
            display: block;
            overflow: hidden;
            // 当前列表切换排序的样式
            &::before {
              content: " ";
              position: absolute;
              left: 0;
              right: 0;
              top: 0;
              height: 3px;
              background: rgb(89, 89, 223);
              z-index: 2;
            }
          }
          // 左边拖拽过来的样式
          .components-item.sortable-ghost {
            width: 100%;
            height: 60px;
            background-color: #f6f7ff;
            color: red;
          }
        }
      }
    </style>
    
    

    vue2demo
    vue3仓库地址

    相关文章

      网友评论

        本文标题:vue3拖拽demo

        本文链接:https://www.haomeiwen.com/subject/kssnrrtx.html