Vue【原创】可拖动列表 darg-list

2023-08-30

拖动排序的列表 drag-list,这个比较简单易懂,拿例子直接运行看效果就好了。

组件代码:

  1 <template>
2 <ul class="list" ref="parentNode" @dragstart="onDragStart" @dragover="onDragOver" @dragend="onDragEnd">
3 <li class="list-item" v-for="(item, index) in dataProvider" :key="item[valueKey]" :id="item[valueKey]"
4 :draggable="draggable">
5 <slot :item="item" :index="index">
6 <div>{{ item }}</div>
7 </slot>
8 </li>
9 </ul>
10 </template>
11
12 <script>
13 const _LI_ = 'LI';
14
15 export default {
16 name: 'LiloDragList',
17 props: {
18 dataProvider: {
19 type: Array,
20 default () {
21 return {}
22 }
23 },
24 draggable: {
25 type: Boolean,
26 default: true
27 },
28 valueKey: {
29 type: String,
30 default: 'id'
31 }
32 },
33 data() {
34 return {
35 draging: null,
36 target: null
37 };
38 },
39 mounted() {
40 document.body.ondrop = event => {
41 event.preventDefault();
42 event.stopPropagation();
43 };
44 },
45 methods: {
46 onDragStart(event) {
47 // console.log('drag start');
48 this.draging = event.target;
49 },
50 onDragOver(event) {
51 // console.log(event.target.nodeName);
52 this.target = event.target;
53 let targetTop = event.target.getBoundingClientRect().top;
54 let dragingTop = this.draging.getBoundingClientRect().top;
55 if (this.target.nodeName === _LI_ && this.target !== this.draging) {
56 if (this.target) {
57 if (this.target.animated) {
58 return;
59 }
60 }
61
62 if (this._index(this.draging) < this._index(this.target)) {
63 this.target.parentNode.insertBefore(this.draging, this.target.nextSibling);
64 } else {
65 this.target.parentNode.insertBefore(this.draging, this.target);
66 }
67 this._anim(targetTop, this.target);
68 this._anim(dragingTop, this.draging);
69 }
70 },
71 _anim(startPos, dom) {
72 let offset = startPos - dom.getBoundingClientRect().top;
73 dom.style.transition = 'none';
74 dom.style.transform = `translateY(${offset}px)`;
75
76 //触发重绘
77 dom.offsetWidth;
78 dom.style.transition = 'transform .3s';
79 dom.style.transform = ``;
80 //触发重绘
81 // setTimeout(()=>{
82 // dom.style.transition="transform .3s";
83 // dom.style.transform=``;
84 // },0)
85 clearTimeout(dom.animated);
86
87 dom.animated = setTimeout(() => {
88 dom.style.transition = '';
89 dom.style.transform = ``;
90 dom.animated = false;
91 }, 300);
92 },
93 onDragEnd(event) {
94 // console.log('drag end');
95 let temp = Array.from(this.$refs.parentNode.childNodes);
96 let currentNodes = temp.filter(node => {
97 return node.nodeName === _LI_
98 })
99 let list = currentNodes.map((i, index) => {
100 let item = this.dataProvider.find(c => {
101 const unikey = i.getAttribute(this.valueKey);
102 const flag = c[this.valueKey] === unikey;
103 return flag;
104 });
105 return item;
106 });
107
108 this.$emit('sorted', list);
109 },
110 _index(el) {
111 let domData = Array.from(this.$refs.parentNode.childNodes);
112 return domData.findIndex(i => i.innerText == el.innerText);
113 }
114 }
115 };
116 </script>
117
118 <style lang="scss" scoped>
119 .list {
120 padding-inline-start: 0;
121
122 .list-item {
123 transition: 0.3s all ease-in;
124 padding: 12px;
125 border-bottom: 1px solid #dbdbdb;
126 list-style: none;
127 margin: 0px;
128
129 &:hover {
130 background-color: #dbdbdb;
131 }
132 }
133 }
134 </style>

调用案例:

 1 <template>
2 <div class="drag-list">
3 <lilo-drag-list :dataProvider="dataProvider" draggable :valueKey="valueKey" @sorted="sorted">
4 <template slot-scope='{ item, index }'>
5 <div>
6 <span class="list-item">index:{{ index }}</span>
7 <span class="list-item">id:{{ item.id }}</span>
8 <span class="list-item">name:{{ item.name }}</span>
9 <span class="list-item">address:{{ item.address }}</span>
10 </div>
11 </template>
12 </lilo-drag-list>
13 </div>
14 </template>
15
16 <script>
17 export default {
18 data() {
19 return {
20 draggable: true, //是否可拖动,默认为true
21 valueKey: 'id', //数据项的唯一标识
22 dataProvider: [
23 { id: 'S001', name: '张三', address: '湖北省武汉市江岸区百步亭花园现代城3区' },
24 { id: 'S002', name: '李四', address: '湖北省武汉市江岸区百步亭花园现代城3区' },
25 { id: 'S003', name: '王五', address: '湖北省武汉市江岸区百步亭花园现代城3区' },
26 { id: 'S004', name: '张飞', address: '湖北省武汉市江岸区百步亭花园现代城3区' },
27 { id: 'S005', name: '关羽', address: '湖北省武汉市江岸区百步亭花园现代城3区' },
28 { id: 'S006', name: '嬴政', address: '湖北省武汉市江岸区百步亭花园现代城3区' },
29 { id: 'S007', name: '廉颇', address: '湖北省武汉市江岸区百步亭花园现代城3区' },
30 { id: 'S008', name: '蒙恬', address: '湖北省武汉市江岸区百步亭花园现代城3区' },
31 { id: 'S009', name: '韩非', address: '湖北省武汉市江岸区百步亭花园现代城3区' }
32 ]
33 }
34 },
35 methods: {
36 sorted(list) { //拖动完成之后触发
37 console.log(list) //改变后的数组顺序
38 console.log(this.dataProvider) //原数据顺序不会被改变
39 }
40 }
41 }
42 </script>
43
44 <style lang="scss" scoped>
45 .drag-list {
46 padding: 10px;
47 .list-item {
48 margin: 0 5px;
49 }
50 }
51 </style>

Vue【原创】可拖动列表 darg-list的相关教程结束。