dragable组件 基于 Sortable的简单封装
<template>
<div :id="id"
class="list-group">
<slot></slot>
</div>
</template>
<script>
import Sortable, { MultiDrag } from 'sortablejs';
Sortable.mount(new MultiDrag());
export default {
props: {
id: String,
group: {
type: Object,
default: () => { return {} }
},
multi: {
type: Boolean,
default: false
},
selectedClass: {
type: String,
default: 'selected'
},
sort: {
type: Boolean,
default: true
}
},
data () {
return {
groupName: 'share'
}
},
mounted () {
this.group['name'] = this.group['name'] || this.groupName
var el = document.getElementById(this.id);
new Sortable(el, {
group: this.group,
multiDrag: this.multi, // Enable the plugin
selectedClass: this.selectedClass, // Class name for selected item
multiDragKey: "CTRL",
ghostClass: 'yellow-background-class',
sort: this.sort,
delay: 0,
setData: (dataTransfer, dragEl) => { this.invoke('setdata', dataTransfer, dragEl) },
onChoose: (evt) => { this.invoke('choose', evt) },
onStart: (evt) => { this.invoke('start', evt) },
onEnd: (evt) => { this.invoke('end', evt) },
onAdd: (evt) => { this.invoke('add', evt) },
onUpdate: (evt) => { this.invoke('update', evt) },
onSort: (evt) => { this.invoke('sort', evt) },
onRemove: (evt) => { this.invoke('remove', evt) },
onMove: (evt, originalEvent) => { this.invoke('move', evt, originalEvent) },
onClone: (evt) => { this.invoke('clone', evt) },
onChange: (evt) => { this.invoke('change', evt) },
onFilter: (evt) => { this.invoke('filter', evt) },
});
},
methods: {
invoke (name, ...args) {
this.$emit(name, ...args)
}
},
}
</script>
<style scoped>
.selected {
border: 1px solid red;
background-color: bisque;
}
.yellow-background-class {
background: #ddd;
}
</style>
基于dragable封装的list组件,支持vue.draggable大多属性设置。
<template>
<dragable-vue :id="dragid"
:group="group"
v-bind="$attrs"
@start="onStart"
@add="onAdd">
<div v-for="(item,index) in valuelist"
:key="index"
:data-value="item[Itemkey]">
<slot name="item"
:row="item"></slot>
</div>
</dragable-vue>
</template>
<script>
import dragableVue from './dragable.vue'
var transfer_data_ = []
function removeNode (node) {
if (node.parentElement !== null) {
node.parentElement.removeChild(node);
}
}
export default {
components: {
dragableVue
},
props: {
value: Array,
group: Object,
unique: {
type: Boolean,
default: false
},
Itemkey: String
},
data () {
return {
valuelist: [],
dragid: `group${Math.random().toString(36).substr(2, 15)}`
}
},
watch: {
value (newvalue) {
this.valuelist = newvalue
}
},
methods: {
onStart (evt) {
let indexs = evt.oldIndicies.length ? evt.oldIndicies.map(item => item.index) : [evt.oldIndex]
transfer_data_ = indexs.map(key => this.valuelist[key])
},
onAdd (evt) {
let index = evt.newIndex
let children = evt.newIndicies.length ? evt.newIndicies.map(item => item.multiDragElement) : [evt.item]
children.forEach(el => {
removeNode(el)
});
let keys = this.valuelist.map(item => item[this.Itemkey]),
tempdata = this.unique ? transfer_data_.filter(item => !keys.includes(item[this.Itemkey])) : transfer_data_
this.valuelist.splice(index, 0, ...tempdata)
this.$emit("input", this.valuelist)
}
}
}
</script>
<style scoped>
</style>
简单测试和使用:
<template>
<div>
<div class="text">
<draglist-vue :group="{pull:'clone',put:false}"
:multi="true"
:sort="false"
class="text-item"
Itemkey="value"
v-model="list1">
<template #item="{row}">
<span v-text="row.label"> </span>
</template>
</draglist-vue>
<draglist-vue v-model="list2"
:unique="true"
Itemkey="value"
class="text-item">
<template #item="{row}"><span v-text="row.label"> </span></template>
</draglist-vue>
</div>
<button @click="handleClick">点我看结果</button>
</div>
</template>
<script>
import draglistVue from './draglist.vue'
export default {
components: {
draglistVue,
},
data () {
return {
list1: [],
list2: []
}
},
mounted () {
this.list1 = [...new Array(10).keys()].map(key => {
let temp = "Item" + key
return { label: temp, value: temp }
})
this.list2 = [...new Array(2).keys()].map(key => {
let temp = "Item" + key
return { label: temp, value: temp }
})
},
methods: {
handleClick () {
console.log(this.list2)
}
},
}
</script>
<style scoped>
.text {
display: flex;
justify-content: space-between;
}
.text-item {
width: 40%;
}
li {
height: 30px;
background-color: aquamarine;
margin-top: 5px;
}
</style>
版本:
“sortablejs”: “^1.14.0”,
“vue”: “^2.5.2”,