demo:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<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>
封装后的组件代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<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>
使用封装后的组件:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<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>