vuedraggable 拖拽组件 封装

demo:

<template>
  <div class="fluid container">
    <div class="form-group form-group-lg panel panel-default">
      <div class="panel-heading">
        <h3 class="panel-title">拖拽组件</h3>
      </div>
      <div class="panel-body">
        <div class="checkbox">
          <label><input type="checkbox" v-model="editable">启用拖拽</label>
        </div>
        <button type="button" class="btn btn-default" @click="orderList">恢复初始排序</button>
      </div>
    </div>
    <div class="box">
        <div class="groupBox">
            <div class="col-md-3">
                <!-- 拖拽元素盒子 -->
              <draggable class="list-group" element="ul" v-model="list" :options="dragOptions" :move="onMove" @start="isDragging=true" @end="isDragging=false">
                <transition-group type="transition" :name="'flip-list'">
                  <li class="list-group-item licommon" v-for="element in list" :key="element.order">
                    <i :class="element.fixed? 'fa fa-anchor' : 'glyphicon glyphicon-pushpin'" @click=" element.fixed=! element.fixed" aria-hidden="true"></i>
                    {{element.name}}
                    <span class="badge">{{element.order}}</span>
                  </li>
                </transition-group>
              </draggable>
            </div>
         </div>
         <div class="groupBox">
             <div class="col-md-3">
                 <!-- 目标元素盒子 -->
               <draggable element="span" v-model="list2" :options="dragOptions" :move="onMove">
                 <transition-group name="no" class="list-group targetUl" tag="ul">
                   <li class="list-group-item" v-for="element in list2" :key="element.order">
                     <i :class="element.fixed? 'fa fa-anchor' : 'glyphicon glyphicon-pushpin'" @click=" element.fixed=! element.fixed" aria-hidden="true"></i>
                     {{element.name}}
                     <span class="badge">{{element.order}}</span>
                   </li>
                 </transition-group>
               </draggable>
             </div>
         </div>
    </div>
    <div class="arr">
        <!-- 拖拽数组 -->
        <div class="list-group col-md-3 arrcommon">
          <pre>{{listString}}</pre>
        </div>
        <!-- 目标数组 -->
        <div class="list-group col-md-3 arrcommon">
          <pre>{{list2String}}</pre>
        </div>
    </div>
  </div>
</template>
 
<script>
import draggable from "vuedraggable";
const message = [
  "詹姆斯",
  "杜兰特",
  "科比",
  "乔丹"
];
 
export default {
  name: "hello",
  components: {
    draggable
  },
  data() {
    return {
      list: message.map((name, index) => {
        return { name, order: index + 1, fixed: false };
      }),
      list2: [],
      editable: true,
      isDragging: false,
      delayedDragging: false
    };
  },
  methods: {
     // 恢复初始排序,已经有拖拽到右边时无法恢复
    orderList() {
      this.list = this.list.sort((one, two) => {
        return one.order - two.order;
      });
    },
    onMove({ relatedContext, draggedContext }) {
      // 关联元素
      const relatedElement = relatedContext.element;
      // 拖拽元素
      const draggedElement = draggedContext.element;
      console.log('拖拽1', relatedElement)
      console.log('拖拽2', draggedElement)
      return (
        (!relatedElement || !relatedElement.fixed) && !draggedElement.fixed
      );
    }
  },
  computed: {
     // 配置项
    dragOptions() {
      return {
        animation: 0,
        group: "description",
        disabled: !this.editable,
        ghostClass: "ghost"
      };
    },
    listString() {
      return JSON.stringify(this.list, null, 2);
    },
    list2String() {
      return JSON.stringify(this.list2, null, 2);
    }
  },
  watch: {
    isDragging(newValue) {
      if (newValue) {
        this.delayedDragging = true;
        return;
      }
      this.$nextTick(() => {
        this.delayedDragging = false;
      });
    }
  }
};
</script>
 
<style>
.box{
    display:flex;
}
.arr{
    display:flex;
}
.arr .arrcommon{
    width:50%;
    border:1px solid red;
}
.targetUl{
    display:flex;
}
.groupBox{
    border:1px solid #00FFFF;
    width:50%;
}
.groupBox li{
    list-style: none;
    height:30px;
    border:1px solid #eeeeee;
}
.flip-list-move {
  transition: transform 0.5s;
}
 
.no-move {
  transition: transform 0s;
}
 
.ghost {
  opacity: 0.5;
  background: #c8ebfb;
}
 
.list-group {
  min-height: 20px;
}
 
.list-group-item {
  cursor: move;
}
 
.list-group-item i {
  cursor: pointer;
}
</style>
View Code

封装后的组件代码:

<template>
  <div class="board-column">
    <div class="board-column-header">
      {{ headerText }}
    </div>
    <draggable
      :list="list"
      v-bind="$attrs"
      class="board-column-content"
      :set-data="setData"
    >
      <div v-for="element in list" :key="element.id" class="board-item">
        {{ element.name }} {{ element.id }}
      </div>
    </draggable>
  </div>
</template>

<script>
import draggable from "vuedraggable";
export default {
  name: "DragKanbanDemo",
  components: {
    draggable,
  },
  props: {
    headerText: {
      type: String,
      default: "Header",
    },
    options: {
      type: Object,
      default() {
        return {};
      },
    },
    list: {
      type: Array,
      default() {
        return [];
      },
    },
  },
  methods: {
    setData(dataTransfer) {
      // to avoid Firefox bug
      // Detail see : https://github.com/RubaXa/Sortable/issues/1012
      dataTransfer.setData("Text", "");
    },
  },
};
</script>
<style lang="less" scoped>
.board-column {
  min-width: 300px;
  min-height: 100px;
  height: auto;
  overflow: hidden;
  background: #f0f0f0;
  border-radius: 3px;
  .board-column-header {
    height: 50px;
    line-height: 50px;
    overflow: hidden;
    padding: 0 20px;
    text-align: center;
    background: #333;
    color: #fff;
    border-radius: 3px 3px 0 0;
  }
  .board-column-content {
    height: auto;
    overflow: hidden;
    border: 10px solid transparent;
    min-height: 60px;
    display: flex;
    justify-content: flex-start;
    flex-direction: column;
    align-items: center;
    .board-item {
      cursor: pointer;
      width: 100%;
      height: 64px;
      margin: 5px 0;
      background-color: #fff;
      text-align: left;
      line-height: 54px;
      padding: 5px 10px;
      box-sizing: border-box;
      box-shadow: 0px 1px 3px 0 rgba(0, 0, 0, 0.2);
    }
  }
}
</style>
View Code

使用封装后的组件:

<template>
  <div class="components-container board">
    <div class="panel-body">
        <div class="checkbox">
          <label><input type="checkbox" v-model="editable" />启用拖拽</label>
        </div>
    </div>

    <Kanban :key="1" :list="list1" :group="group" :disabled="!this.editable" class="kanban todo" header-text="Todo" />
    <Kanban :key="2" :list="list2" :group="group" :disabled="!this.editable" class="kanban working" header-text="Working" />
    <Kanban :key="3" :list="list3" :group="group" :disabled="!this.editable" class="kanban done" header-text="Done" />
  </div>
</template>
<script>
import Kanban from '@/components/Kanban'
export default {
  name: 'DragKanbanDemo',
  components: {
    Kanban
  },
  data() {
    return {
      editable: true,
      group: 'mission',
      list1: [
        { name: 'Mission', id: 1 },
        { name: 'Mission', id: 2 },
        { name: 'Mission', id: 3 },
        { name: 'Mission', id: 4 }
      ],
      list2: [
        { name: 'Mission', id: 5 },
        { name: 'Mission', id: 6 },
        { name: 'Mission', id: 7 }
      ],
      list3: [
        { name: 'Mission', id: 8 },
        { name: 'Mission', id: 9 },
        { name: 'Mission', id: 10 }
      ]
    }
  },
}
</script>
<style lang="less">
.board {
  width: 1000px;
  margin-left: 20px;
  display: flex;
  justify-content: space-around;
  flex-direction: row;
  align-items: flex-start;
}
.kanban {
  &.todo {
    .board-column-header {
      background: #4A9FF9;
    }
  }
  &.working {
    .board-column-header {
      background: #f9944a;
    }
  }
  &.done {
    .board-column-header {
      background: #2ac06d;
    }
  }
}
</style>
View Code
原文地址:https://www.cnblogs.com/jervy/p/14303551.html