Skip to content

Commit 3fb0659

Browse files
author
jxl
committed
fix sortable bug
1 parent 4d1acfe commit 3fb0659

File tree

5 files changed

+125
-35
lines changed

5 files changed

+125
-35
lines changed

CHANGELOG.md

+13
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
## 2023-3-1(v: 3.0.0)
2+
3+
- 升级:全新升级登录页面和首页面UI
4+
5+
- 修复:全新设计并修复 `SortableTable.vue` 组件报错问题。
6+
涉及文件如下:
7+
- src/components/SortableTable.vue
8+
- src/types/components.ts
9+
- package.json (新增第三方依赖:sortablejs 声明依赖:@types/sortablejs
10+
11+
- 修复:添加 `@typescript-eslint/parser` eslint 依赖,修复在某些情况下报错信息:
12+
`Parsing error: Cannot find module '@typescript-eslint/parser'`
13+
114
## 2023-2-20(v: 2.1.0)
215

316
- 优化:优化`路由``fullPath` 字段为主键,以支持相同路由,query参数不一致时导致路由参数缺失

package.json

+3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"qrcode": "^1.5.0",
2525
"qs": "^6.10.1",
2626
"quill": "^1.3.7",
27+
"sortablejs": "^1.15.0",
2728
"tiny-emitter": "^2.1.0",
2829
"vue": "^3.2.31",
2930
"vue-router": "^4.0.14",
@@ -39,7 +40,9 @@
3940
"@types/qrcode": "^1.4.1",
4041
"@types/qs": "^6.9.7",
4142
"@types/quill": "^2.0.9",
43+
"@types/sortablejs": "^1.15.0",
4244
"@typescript-eslint/eslint-plugin": "^5.44.0",
45+
"@typescript-eslint/parser": "^5.54.1",
4346
"@vitejs/plugin-vue": "^3.1.2",
4447
"@vitejs/plugin-vue-jsx": "^1.3.10",
4548
"autoprefixer": "^10.4.0",

pnpm-lock.yaml

+44-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/SortableTable.vue

+64-32
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,19 @@
11
<template>
2-
<a-popover :style="{ width: '200px' }" trigger="click">
2+
<a-popover :style="{ width: '200px' }" trigger="click" @popup-visible-change="onPopVisibleChange">
33
<template #content>
44
<div style="border-bottom: 1px solid #f5f5f5" class="flex items-center justify-between">
55
<a-checkbox v-model="allChecked" @change="onAllChange"> 全选 </a-checkbox>
66
<a-button type="text" class="text-right" @click="onReset"> 重置 </a-button>
77
</div>
8-
<draggable
9-
:list="innerTableProps"
10-
animation="500"
11-
tag="transition-group"
12-
item-key="key"
13-
@end="onUpdateValue"
14-
>
15-
<template #item="{ element }">
16-
<div class="flex pt-2 pb-2">
17-
<a-checkbox v-model="element.checked" :label="element.prop" @change="onChange">
18-
{{ element.title }}
19-
</a-checkbox>
20-
<div class="flex-1"></div>
21-
<icon-menu />
22-
</div>
23-
</template>
24-
</draggable>
8+
<div class="pt-2 pb-2" id="sortColumnWrapper">
9+
<div class="column-item" v-for="item of innerTableProps" :key="item.key">
10+
<a-checkbox v-model="item.checked" :label="item.title" @change="onChange">
11+
{{ item.title }}
12+
</a-checkbox>
13+
<div class="flex-1"></div>
14+
<icon-menu class="handle-icon" />
15+
</div>
16+
</div>
2517
</template>
2618
<a-button type="primary" size="small" shape="circle">
2719
<template #icon>
@@ -33,11 +25,11 @@
3325

3426
<script lang="ts">
3527
import { TablePropsType } from '@/types/components'
36-
import { defineComponent, PropType, reactive, ref, toRef } from 'vue'
37-
import draggable from 'vuedraggable'
28+
import { defineComponent, PropType, reactive, ref, toRef, nextTick } from 'vue'
29+
import Sortable from 'sortablejs'
30+
import { cloneDeep, isUndefined } from 'lodash-es'
3831
export default defineComponent({
3932
name: 'SortableTable',
40-
components: { draggable },
4133
props: {
4234
columns: {
4335
type: Array as PropType<TablePropsType[]>,
@@ -47,40 +39,66 @@
4739
emits: ['update'],
4840
setup(props, { emit }) {
4941
const tempTableProps = toRef(props, 'columns')
42+
const originColumns = cloneDeep<TablePropsType[]>(tempTableProps.value!)
5043
const tempArray =
5144
tempTableProps.value
5245
?.filter((it) => !!it.key)
5346
.map((it) => {
5447
return {
5548
...it,
56-
checked: ref(true),
49+
checked: true,
5750
} as TablePropsType
5851
}) || []
59-
const innerTableProps = reactive(tempArray)
52+
const innerTableProps = reactive<TablePropsType[]>(tempArray)
6053
const isIndeterminate = ref(
6154
innerTableProps.filter((it) => it.checked).length !== innerTableProps.length
6255
)
6356
const allChecked = ref(innerTableProps.every((it) => it.checked))
6457
function onAllChange(value: any) {
65-
innerTableProps.forEach((it) => (it.checked = value?.target?.checked))
66-
emit(
67-
'update',
68-
innerTableProps.filter((it) => it.checked)
69-
)
58+
innerTableProps.forEach((it) => (it.checked = value))
59+
onUpdateValue(innerTableProps.filter((it) => it.checked))
7060
}
7161
const onChange = () => {
7262
const checkedItems = innerTableProps.filter((it) => it.checked)
7363
allChecked.value = checkedItems.length === innerTableProps.length
7464
isIndeterminate.value =
7565
checkedItems.length > 0 && checkedItems.length !== innerTableProps.length
76-
emit('update', checkedItems)
66+
onUpdateValue(checkedItems)
7767
}
7868
const onReset = () => {
69+
innerTableProps.length = 0
70+
innerTableProps.push(...originColumns)
7971
innerTableProps.forEach((it) => (it.checked = true))
80-
onChange()
72+
allChecked.value = true
73+
onUpdateValue(innerTableProps)
74+
}
75+
function onUpdateValue(columns: TablePropsType[]) {
76+
emit('update', columns)
8177
}
82-
function onUpdateValue() {
83-
emit('update', innerTableProps)
78+
function onPopVisibleChange(visible: boolean) {
79+
if (visible) {
80+
nextTick(() => {
81+
new Sortable(document.getElementById('sortColumnWrapper') as HTMLElement, {
82+
handle: '.handle-icon',
83+
animation: 150,
84+
dataIdAttr: '',
85+
onEnd({ newIndex, oldIndex }) {
86+
if (isUndefined(newIndex) || isUndefined(oldIndex)) {
87+
return
88+
}
89+
const originItem = innerTableProps[oldIndex]
90+
if (newIndex > oldIndex) {
91+
innerTableProps.splice(newIndex + 1, 0, originItem)
92+
innerTableProps.splice(oldIndex, 1)
93+
} else {
94+
innerTableProps.splice(newIndex, 0, originItem)
95+
innerTableProps.splice(oldIndex + 1, 1)
96+
}
97+
onUpdateValue(innerTableProps)
98+
},
99+
})
100+
})
101+
}
84102
}
85103
return {
86104
innerTableProps,
@@ -90,7 +108,21 @@
90108
onChange,
91109
onReset,
92110
onUpdateValue,
111+
onPopVisibleChange,
93112
}
94113
},
95114
})
96115
</script>
116+
117+
<style lang="less" scoped>
118+
.column-item {
119+
display: flex;
120+
align-items: center;
121+
padding: 8px 0;
122+
.handle-icon {
123+
&:hover {
124+
cursor: move;
125+
}
126+
}
127+
}
128+
</style>

src/types/components.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export interface TablePropsType {
5454
title: string
5555
key: string
5656
sortIndex: number
57-
checked: Ref<boolean>
57+
checked: boolean
5858
}
5959

6060
// export type ModalDialogType = InstanceType<typeof ModalDialog>

0 commit comments

Comments
 (0)