@lx-frontend/wrap-element-ui 1.0.1-beta.3 → 1.0.1-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -45
- package/package.json +14 -14
- package/src/components/AddMembers/index.vue +157 -157
- package/src/components/AuditSteps/index.vue +140 -140
- package/src/components/DemoComponent/index.vue +20 -20
- package/src/components/EditableTable/README.md +147 -147
- package/src/components/EditableTable/index.less +724 -724
- package/src/components/EditableTable/index.vue +914 -914
- package/src/components/EditableTable/types.ts +116 -116
- package/src/components/EditableTable/useCellHover.ts +71 -71
- package/src/components/EditableTable/useColumnHeaderOperation.ts +325 -325
- package/src/components/EditableTable/useDefaultOperation.ts +95 -95
- package/src/components/EditableTable/useDragSort.ts +290 -290
- package/src/components/EditableTable/usePagination.ts +30 -30
- package/src/components/EditableTable/useRowBgColor.ts +50 -50
- package/src/components/EditableTable/useViewSetting.ts +119 -119
- package/src/components/Ellipsis/MultilineEllipsis.vue +141 -141
- package/src/components/Ellipsis/index.vue +119 -119
- package/src/components/LxTable/index.vue +296 -296
- package/src/components/PopoverForm/index.vue +66 -66
- package/src/components/SearchForm/index.vue +243 -243
- package/src/components/SearchSelect/index.vue +153 -153
- package/src/components/index.ts +24 -24
- package/src/components/singleMessage/index.ts +44 -44
|
@@ -1,51 +1,51 @@
|
|
|
1
|
-
import { ref, nextTick } from "vue"
|
|
2
|
-
import { IColorList, IEmits } from "./types"
|
|
3
|
-
|
|
4
|
-
interface IUseRowBgColorParams {
|
|
5
|
-
colorList: IColorList;
|
|
6
|
-
emit: IEmits;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export default function useRowBgColor({ colorList, emit }: IUseRowBgColorParams) {
|
|
10
|
-
const colorPopoverRef = ref<any>(null);
|
|
11
|
-
|
|
12
|
-
const isDefaultColor = (id: number) => {
|
|
13
|
-
if (!id) {
|
|
14
|
-
// 没有颜色id,则认为是默认色
|
|
15
|
-
return true;
|
|
16
|
-
}
|
|
17
|
-
return colorList.find(c => +c.id === +id)?.default;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const getColorById = (id: number, type: 'bg' | 'sample' = 'bg') => {
|
|
21
|
-
return colorList.find(c => +c.id === +id)?.[`${type}Color`] || '';
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const setRowStyle = (scope) => {
|
|
25
|
-
const row = scope.row;
|
|
26
|
-
return {
|
|
27
|
-
backgroundColor: row.colorId ? getColorById(row.colorId) : ''
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const handleColorChange = async (colorId: number, scope) => {
|
|
32
|
-
const { row, $index: rowIndex, store } = scope;
|
|
33
|
-
const dataList = store.states.data;
|
|
34
|
-
const curRow = { ...dataList[rowIndex], colorId: +colorId };
|
|
35
|
-
const newList = [...dataList];
|
|
36
|
-
newList.splice(rowIndex, 1, curRow);
|
|
37
|
-
store.states.data = newList;
|
|
38
|
-
emit('row-bg-change', { colorId, row, rowIndex });
|
|
39
|
-
await nextTick();
|
|
40
|
-
// TODO: 为什么不是数组?为什么关闭弹窗不生效了?
|
|
41
|
-
colorPopoverRef.value?.doClose();
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return {
|
|
45
|
-
isDefaultColor,
|
|
46
|
-
getColorById,
|
|
47
|
-
setRowStyle,
|
|
48
|
-
handleColorChange,
|
|
49
|
-
colorPopoverRef
|
|
50
|
-
}
|
|
1
|
+
import { ref, nextTick } from "vue"
|
|
2
|
+
import { IColorList, IEmits } from "./types"
|
|
3
|
+
|
|
4
|
+
interface IUseRowBgColorParams {
|
|
5
|
+
colorList: IColorList;
|
|
6
|
+
emit: IEmits;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export default function useRowBgColor({ colorList, emit }: IUseRowBgColorParams) {
|
|
10
|
+
const colorPopoverRef = ref<any>(null);
|
|
11
|
+
|
|
12
|
+
const isDefaultColor = (id: number) => {
|
|
13
|
+
if (!id) {
|
|
14
|
+
// 没有颜色id,则认为是默认色
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
return colorList.find(c => +c.id === +id)?.default;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const getColorById = (id: number, type: 'bg' | 'sample' = 'bg') => {
|
|
21
|
+
return colorList.find(c => +c.id === +id)?.[`${type}Color`] || '';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const setRowStyle = (scope) => {
|
|
25
|
+
const row = scope.row;
|
|
26
|
+
return {
|
|
27
|
+
backgroundColor: row.colorId ? getColorById(row.colorId) : ''
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const handleColorChange = async (colorId: number, scope) => {
|
|
32
|
+
const { row, $index: rowIndex, store } = scope;
|
|
33
|
+
const dataList = store.states.data;
|
|
34
|
+
const curRow = { ...dataList[rowIndex], colorId: +colorId };
|
|
35
|
+
const newList = [...dataList];
|
|
36
|
+
newList.splice(rowIndex, 1, curRow);
|
|
37
|
+
store.states.data = newList;
|
|
38
|
+
emit('row-bg-change', { colorId, row, rowIndex });
|
|
39
|
+
await nextTick();
|
|
40
|
+
// TODO: 为什么不是数组?为什么关闭弹窗不生效了?
|
|
41
|
+
colorPopoverRef.value?.doClose();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
isDefaultColor,
|
|
46
|
+
getColorById,
|
|
47
|
+
setRowStyle,
|
|
48
|
+
handleColorChange,
|
|
49
|
+
colorPopoverRef
|
|
50
|
+
}
|
|
51
51
|
}
|
|
@@ -1,119 +1,119 @@
|
|
|
1
|
-
import { ref, nextTick, watch, ComputedRef, Ref, onMounted, computed } from "vue"
|
|
2
|
-
import { IColumnConfig, IProps } from "./types"
|
|
3
|
-
|
|
4
|
-
interface IViewSettingParams {
|
|
5
|
-
tableDomRef: any
|
|
6
|
-
showingColumns: Ref<string[]>
|
|
7
|
-
actualColumns: ComputedRef<IColumnConfig[]>
|
|
8
|
-
props: IProps
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export default function useViewSetting({ tableDomRef, showingColumns, actualColumns, props }: IViewSettingParams) {
|
|
12
|
-
const viewSettingDragSortOptions = ref<IColumnConfig[]>([]);
|
|
13
|
-
const columnsToBeShown = ref<string[]>([]); // 显示设置弹窗中勾选的列
|
|
14
|
-
const viewSettingVisible = ref(false);
|
|
15
|
-
const leftFixedColumnCount = ref(0);
|
|
16
|
-
const tempLeftFixedColumnCount = ref(0);
|
|
17
|
-
|
|
18
|
-
const storageKey = computed(() => `@lx-frontend/wrap-element-ui/table_setting_cloumns/${props.settingStorgeKey || (location.pathname === '/' ? location.hash : location.pathname)}`);
|
|
19
|
-
|
|
20
|
-
const saveSettingToStorge = () => localStorage.setItem(storageKey.value, JSON.stringify({
|
|
21
|
-
showingColumns: showingColumns.value,
|
|
22
|
-
leftFixedColumnCount: leftFixedColumnCount.value
|
|
23
|
-
}));
|
|
24
|
-
|
|
25
|
-
watch(
|
|
26
|
-
() => props.columnConfig,
|
|
27
|
-
(val) => {
|
|
28
|
-
const _keys = new Set(props.columnConfig.map(c => (c.prop)));
|
|
29
|
-
const _cache = localStorage.getItem(storageKey.value);
|
|
30
|
-
const setColumns = () => (showingColumns.value = val.filter(v => !v.defaultHide).map(c => c.prop));
|
|
31
|
-
if (!_cache) {
|
|
32
|
-
setColumns();
|
|
33
|
-
leftFixedColumnCount.value = props.leftFixedCount as number;
|
|
34
|
-
} else {
|
|
35
|
-
try {
|
|
36
|
-
// 缓存数据字段可能随着更新导致对不上,清理无效数据,防止出问题
|
|
37
|
-
const cache = JSON.parse(_cache);
|
|
38
|
-
if (!cache.showingColumns || !Array.isArray(cache.showingColumns)) {
|
|
39
|
-
setColumns();
|
|
40
|
-
} else {
|
|
41
|
-
showingColumns.value = cache.showingColumns.filter(key => _keys.has(key));
|
|
42
|
-
}
|
|
43
|
-
const _leftFixedColumnCount = Number(cache?.leftFixedColumnCount)
|
|
44
|
-
leftFixedColumnCount.value = isNaN(_leftFixedColumnCount) ? (props.leftFixedCount as number) : _leftFixedColumnCount;
|
|
45
|
-
// 写入清理后的数据
|
|
46
|
-
saveSettingToStorge();
|
|
47
|
-
} catch (error) {
|
|
48
|
-
console.error(error);
|
|
49
|
-
localStorage.removeItem(storageKey.value);
|
|
50
|
-
setColumns();
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
},
|
|
54
|
-
{ immediate: true }
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
watch(
|
|
58
|
-
() => columnsToBeShown.value,
|
|
59
|
-
(val) => {
|
|
60
|
-
viewSettingDragSortOptions.value = props.columnConfig
|
|
61
|
-
.filter(c => val.includes(c.prop));
|
|
62
|
-
if (tempLeftFixedColumnCount.value > val.length) tempLeftFixedColumnCount.value = val.length
|
|
63
|
-
},
|
|
64
|
-
{ immediate: true }
|
|
65
|
-
)
|
|
66
|
-
|
|
67
|
-
watch(
|
|
68
|
-
() => showingColumns.value,
|
|
69
|
-
(val) => {
|
|
70
|
-
// 只要正在显示的列发生变化,dialog中的显示项也要同步变化,反之不然
|
|
71
|
-
columnsToBeShown.value = [...val];
|
|
72
|
-
},
|
|
73
|
-
{ immediate: true }
|
|
74
|
-
)
|
|
75
|
-
|
|
76
|
-
onMounted(() => {
|
|
77
|
-
leftFixedColumnCount.value = props.leftFixedCount as number;
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
const handleViewSettingShow = () => {
|
|
81
|
-
viewSettingDragSortOptions.value = actualColumns.value
|
|
82
|
-
.filter(c => columnsToBeShown.value.includes(c.prop));
|
|
83
|
-
tempLeftFixedColumnCount.value = leftFixedColumnCount.value;
|
|
84
|
-
viewSettingVisible.value = true;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const handleViewSettingClose = () => {
|
|
88
|
-
viewSettingVisible.value = false;
|
|
89
|
-
// 恢复显示的列
|
|
90
|
-
showingColumns.value = actualColumns.value.map(c => c.prop);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const handleViewSettingConfirm = async () => {
|
|
94
|
-
viewSettingVisible.value = false;
|
|
95
|
-
showingColumns.value = viewSettingDragSortOptions.value.map(c => c.prop);
|
|
96
|
-
leftFixedColumnCount.value = tempLeftFixedColumnCount.value;
|
|
97
|
-
saveSettingToStorge()
|
|
98
|
-
await nextTick();
|
|
99
|
-
tableDomRef.value?.doLayout();
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const handleInputTempLeftFixedColumnCount = (value: string) => {
|
|
103
|
-
const _value = Number(value)
|
|
104
|
-
if (isNaN(_value)) return
|
|
105
|
-
tempLeftFixedColumnCount.value = Math.max(0, Math.min(columnsToBeShown.value.length, Math.floor(_value)))
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return {
|
|
109
|
-
viewSettingDragSortOptions,
|
|
110
|
-
columnsToBeShown,
|
|
111
|
-
viewSettingVisible,
|
|
112
|
-
leftFixedColumnCount,
|
|
113
|
-
tempLeftFixedColumnCount,
|
|
114
|
-
handleInputTempLeftFixedColumnCount,
|
|
115
|
-
handleViewSettingShow,
|
|
116
|
-
handleViewSettingClose,
|
|
117
|
-
handleViewSettingConfirm
|
|
118
|
-
}
|
|
119
|
-
}
|
|
1
|
+
import { ref, nextTick, watch, ComputedRef, Ref, onMounted, computed } from "vue"
|
|
2
|
+
import { IColumnConfig, IProps } from "./types"
|
|
3
|
+
|
|
4
|
+
interface IViewSettingParams {
|
|
5
|
+
tableDomRef: any
|
|
6
|
+
showingColumns: Ref<string[]>
|
|
7
|
+
actualColumns: ComputedRef<IColumnConfig[]>
|
|
8
|
+
props: IProps
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default function useViewSetting({ tableDomRef, showingColumns, actualColumns, props }: IViewSettingParams) {
|
|
12
|
+
const viewSettingDragSortOptions = ref<IColumnConfig[]>([]);
|
|
13
|
+
const columnsToBeShown = ref<string[]>([]); // 显示设置弹窗中勾选的列
|
|
14
|
+
const viewSettingVisible = ref(false);
|
|
15
|
+
const leftFixedColumnCount = ref(0);
|
|
16
|
+
const tempLeftFixedColumnCount = ref(0);
|
|
17
|
+
|
|
18
|
+
const storageKey = computed(() => `@lx-frontend/wrap-element-ui/table_setting_cloumns/${props.settingStorgeKey || (location.pathname === '/' ? location.hash : location.pathname)}`);
|
|
19
|
+
|
|
20
|
+
const saveSettingToStorge = () => localStorage.setItem(storageKey.value, JSON.stringify({
|
|
21
|
+
showingColumns: showingColumns.value,
|
|
22
|
+
leftFixedColumnCount: leftFixedColumnCount.value
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
watch(
|
|
26
|
+
() => props.columnConfig,
|
|
27
|
+
(val) => {
|
|
28
|
+
const _keys = new Set(props.columnConfig.map(c => (c.prop)));
|
|
29
|
+
const _cache = localStorage.getItem(storageKey.value);
|
|
30
|
+
const setColumns = () => (showingColumns.value = val.filter(v => !v.defaultHide).map(c => c.prop));
|
|
31
|
+
if (!_cache) {
|
|
32
|
+
setColumns();
|
|
33
|
+
leftFixedColumnCount.value = props.leftFixedCount as number;
|
|
34
|
+
} else {
|
|
35
|
+
try {
|
|
36
|
+
// 缓存数据字段可能随着更新导致对不上,清理无效数据,防止出问题
|
|
37
|
+
const cache = JSON.parse(_cache);
|
|
38
|
+
if (!cache.showingColumns || !Array.isArray(cache.showingColumns)) {
|
|
39
|
+
setColumns();
|
|
40
|
+
} else {
|
|
41
|
+
showingColumns.value = cache.showingColumns.filter(key => _keys.has(key));
|
|
42
|
+
}
|
|
43
|
+
const _leftFixedColumnCount = Number(cache?.leftFixedColumnCount)
|
|
44
|
+
leftFixedColumnCount.value = isNaN(_leftFixedColumnCount) ? (props.leftFixedCount as number) : _leftFixedColumnCount;
|
|
45
|
+
// 写入清理后的数据
|
|
46
|
+
saveSettingToStorge();
|
|
47
|
+
} catch (error) {
|
|
48
|
+
console.error(error);
|
|
49
|
+
localStorage.removeItem(storageKey.value);
|
|
50
|
+
setColumns();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
{ immediate: true }
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
watch(
|
|
58
|
+
() => columnsToBeShown.value,
|
|
59
|
+
(val) => {
|
|
60
|
+
viewSettingDragSortOptions.value = props.columnConfig
|
|
61
|
+
.filter(c => val.includes(c.prop));
|
|
62
|
+
if (tempLeftFixedColumnCount.value > val.length) tempLeftFixedColumnCount.value = val.length
|
|
63
|
+
},
|
|
64
|
+
{ immediate: true }
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
watch(
|
|
68
|
+
() => showingColumns.value,
|
|
69
|
+
(val) => {
|
|
70
|
+
// 只要正在显示的列发生变化,dialog中的显示项也要同步变化,反之不然
|
|
71
|
+
columnsToBeShown.value = [...val];
|
|
72
|
+
},
|
|
73
|
+
{ immediate: true }
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
onMounted(() => {
|
|
77
|
+
leftFixedColumnCount.value = props.leftFixedCount as number;
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
const handleViewSettingShow = () => {
|
|
81
|
+
viewSettingDragSortOptions.value = actualColumns.value
|
|
82
|
+
.filter(c => columnsToBeShown.value.includes(c.prop));
|
|
83
|
+
tempLeftFixedColumnCount.value = leftFixedColumnCount.value;
|
|
84
|
+
viewSettingVisible.value = true;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const handleViewSettingClose = () => {
|
|
88
|
+
viewSettingVisible.value = false;
|
|
89
|
+
// 恢复显示的列
|
|
90
|
+
showingColumns.value = actualColumns.value.map(c => c.prop);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const handleViewSettingConfirm = async () => {
|
|
94
|
+
viewSettingVisible.value = false;
|
|
95
|
+
showingColumns.value = viewSettingDragSortOptions.value.map(c => c.prop);
|
|
96
|
+
leftFixedColumnCount.value = tempLeftFixedColumnCount.value;
|
|
97
|
+
saveSettingToStorge()
|
|
98
|
+
await nextTick();
|
|
99
|
+
tableDomRef.value?.doLayout();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const handleInputTempLeftFixedColumnCount = (value: string) => {
|
|
103
|
+
const _value = Number(value)
|
|
104
|
+
if (isNaN(_value)) return
|
|
105
|
+
tempLeftFixedColumnCount.value = Math.max(0, Math.min(columnsToBeShown.value.length, Math.floor(_value)))
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
viewSettingDragSortOptions,
|
|
110
|
+
columnsToBeShown,
|
|
111
|
+
viewSettingVisible,
|
|
112
|
+
leftFixedColumnCount,
|
|
113
|
+
tempLeftFixedColumnCount,
|
|
114
|
+
handleInputTempLeftFixedColumnCount,
|
|
115
|
+
handleViewSettingShow,
|
|
116
|
+
handleViewSettingClose,
|
|
117
|
+
handleViewSettingConfirm
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -1,141 +1,141 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="ellipsis">
|
|
3
|
-
<div class="ellipsis__container" :style="{ 'font-size': `${fontSize}px`, 'line-height': lineHeight, color }">
|
|
4
|
-
<div class="ellipsis__content" ref="contentEl" :style="{ height: `${preHeight}px`, 'align-items': alignItems }">{{ preContent }}</div>
|
|
5
|
-
<div class="ellipsis__last-line" ref="lastLineEl" :style="{ height: `${lastLineHeight}px` }">{{ restContent }}
|
|
6
|
-
<span v-if="isShowIconMethod()" :class="iconName"></span>
|
|
7
|
-
</div>
|
|
8
|
-
</div>
|
|
9
|
-
</div>
|
|
10
|
-
</template>
|
|
11
|
-
|
|
12
|
-
<script>
|
|
13
|
-
export default {
|
|
14
|
-
name: 'MultilineEllipsis',
|
|
15
|
-
props: {
|
|
16
|
-
fontSize: {
|
|
17
|
-
type: Number,
|
|
18
|
-
default: 12
|
|
19
|
-
},
|
|
20
|
-
color: {
|
|
21
|
-
type: String,
|
|
22
|
-
default: '#000000'
|
|
23
|
-
},
|
|
24
|
-
lineCount: {
|
|
25
|
-
type: Number,
|
|
26
|
-
default: 1
|
|
27
|
-
},
|
|
28
|
-
content: {
|
|
29
|
-
type: String,
|
|
30
|
-
default: ''
|
|
31
|
-
},
|
|
32
|
-
isOverflow: {
|
|
33
|
-
type: Boolean,
|
|
34
|
-
default: false
|
|
35
|
-
},
|
|
36
|
-
iconName: {
|
|
37
|
-
type: String,
|
|
38
|
-
default: 'el-icon-arrow-down'
|
|
39
|
-
},
|
|
40
|
-
overCountTip: {
|
|
41
|
-
type: Object,
|
|
42
|
-
},
|
|
43
|
-
showIconObj: {
|
|
44
|
-
type: Object,
|
|
45
|
-
default: () => {
|
|
46
|
-
return {
|
|
47
|
-
isShowIcon: false,
|
|
48
|
-
length: 0,
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
data () {
|
|
54
|
-
return {
|
|
55
|
-
restContent: '',
|
|
56
|
-
preContent: '',
|
|
57
|
-
lastLineHeight: 0,
|
|
58
|
-
alignItems: 'center'
|
|
59
|
-
}
|
|
60
|
-
},
|
|
61
|
-
computed: {
|
|
62
|
-
preHeight () {
|
|
63
|
-
return (this.fontSize + 2) * (this.lineCount - 1)
|
|
64
|
-
},
|
|
65
|
-
lineHeight () {
|
|
66
|
-
return `${this.fontSize + 2}px`
|
|
67
|
-
}
|
|
68
|
-
},
|
|
69
|
-
mounted () {
|
|
70
|
-
// 由于在 element table 中,渲染计算时的宽度可能与实际展示时的宽度可能存在偏差,在此把宽度固定为组件挂载时获取到的宽度
|
|
71
|
-
this.$refs.contentEl.style.width = `${this.$refs.contentEl.offsetWidth}px`
|
|
72
|
-
// 处理长度为1的数据不用走截取逻辑减少计算
|
|
73
|
-
if (this.content.length === 1) {
|
|
74
|
-
this.restContent = this.content;
|
|
75
|
-
this.$refs.contentEl.remove();
|
|
76
|
-
this.lastLineHeight = (this.fontSize + 2);
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
this.bsearch(this.content)
|
|
80
|
-
this.lastLineHeight = (this.fontSize + 2)
|
|
81
|
-
},
|
|
82
|
-
methods: {
|
|
83
|
-
bsearch (data, pre = 0) {
|
|
84
|
-
const len = data.length
|
|
85
|
-
const half = Math.floor((len - pre) / 2) + pre
|
|
86
|
-
if (len - pre <= 1) {
|
|
87
|
-
const restContent = pre === 0 ? this.content.slice(pre) : this.content.slice(pre + 1)
|
|
88
|
-
this.preContent = pre === 0 ? '' : data.slice(0, pre + 1)
|
|
89
|
-
if (!restContent) {
|
|
90
|
-
this.lastLineHeight = 0
|
|
91
|
-
this.$emit('update:isOverflow', false)
|
|
92
|
-
return false
|
|
93
|
-
}
|
|
94
|
-
this.restContent = restContent
|
|
95
|
-
this.$nextTick(() => {
|
|
96
|
-
this.$emit('update:isOverflow', this.$refs.lastLineEl.scrollWidth !== this.$refs.lastLineEl.offsetWidth)
|
|
97
|
-
})
|
|
98
|
-
return true
|
|
99
|
-
}
|
|
100
|
-
this.preContent = data.slice(0, half + 1)
|
|
101
|
-
this.$nextTick(() => {
|
|
102
|
-
const isEqual = this.$refs.contentEl.scrollHeight === this.preHeight
|
|
103
|
-
if (isEqual) {
|
|
104
|
-
this.alignItems = 'center'
|
|
105
|
-
return this.bsearch(data, half)
|
|
106
|
-
}
|
|
107
|
-
this.alignItems = 'flex-start'
|
|
108
|
-
return this.bsearch(data.slice(0, half), pre)
|
|
109
|
-
})
|
|
110
|
-
return true
|
|
111
|
-
},
|
|
112
|
-
isShowIconMethod() {
|
|
113
|
-
/**
|
|
114
|
-
* 1、isShowIcon--是否展示icon; length-- 所有传入数据总数量
|
|
115
|
-
* 2、this.overCountTip.index === this.overCountTip.length 当前列表展示个数(最后一个列)
|
|
116
|
-
* 3、length > this.overCountTip.length 满足总个数大于当前列表展示个数
|
|
117
|
-
**/
|
|
118
|
-
const { isShowIcon, length } = this.showIconObj;
|
|
119
|
-
return (isShowIcon && this.overCountTip.index === this.overCountTip.length && this.content.length && (length > this.overCountTip.length));
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
</script>
|
|
124
|
-
|
|
125
|
-
<style lang="less">
|
|
126
|
-
.ellipsis {
|
|
127
|
-
width: 100%;
|
|
128
|
-
margin: 5px auto;
|
|
129
|
-
&__content {
|
|
130
|
-
width: 100%;
|
|
131
|
-
overflow: hidden;
|
|
132
|
-
display: flex;
|
|
133
|
-
}
|
|
134
|
-
&__last-line {
|
|
135
|
-
width: 100%;
|
|
136
|
-
overflow: hidden;
|
|
137
|
-
white-space: nowrap;
|
|
138
|
-
text-overflow: ellipsis;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
</style>
|
|
1
|
+
<template>
|
|
2
|
+
<div class="ellipsis">
|
|
3
|
+
<div class="ellipsis__container" :style="{ 'font-size': `${fontSize}px`, 'line-height': lineHeight, color }">
|
|
4
|
+
<div class="ellipsis__content" ref="contentEl" :style="{ height: `${preHeight}px`, 'align-items': alignItems }">{{ preContent }}</div>
|
|
5
|
+
<div class="ellipsis__last-line" ref="lastLineEl" :style="{ height: `${lastLineHeight}px` }">{{ restContent }}
|
|
6
|
+
<span v-if="isShowIconMethod()" :class="iconName"></span>
|
|
7
|
+
</div>
|
|
8
|
+
</div>
|
|
9
|
+
</div>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<script>
|
|
13
|
+
export default {
|
|
14
|
+
name: 'MultilineEllipsis',
|
|
15
|
+
props: {
|
|
16
|
+
fontSize: {
|
|
17
|
+
type: Number,
|
|
18
|
+
default: 12
|
|
19
|
+
},
|
|
20
|
+
color: {
|
|
21
|
+
type: String,
|
|
22
|
+
default: '#000000'
|
|
23
|
+
},
|
|
24
|
+
lineCount: {
|
|
25
|
+
type: Number,
|
|
26
|
+
default: 1
|
|
27
|
+
},
|
|
28
|
+
content: {
|
|
29
|
+
type: String,
|
|
30
|
+
default: ''
|
|
31
|
+
},
|
|
32
|
+
isOverflow: {
|
|
33
|
+
type: Boolean,
|
|
34
|
+
default: false
|
|
35
|
+
},
|
|
36
|
+
iconName: {
|
|
37
|
+
type: String,
|
|
38
|
+
default: 'el-icon-arrow-down'
|
|
39
|
+
},
|
|
40
|
+
overCountTip: {
|
|
41
|
+
type: Object,
|
|
42
|
+
},
|
|
43
|
+
showIconObj: {
|
|
44
|
+
type: Object,
|
|
45
|
+
default: () => {
|
|
46
|
+
return {
|
|
47
|
+
isShowIcon: false,
|
|
48
|
+
length: 0,
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
data () {
|
|
54
|
+
return {
|
|
55
|
+
restContent: '',
|
|
56
|
+
preContent: '',
|
|
57
|
+
lastLineHeight: 0,
|
|
58
|
+
alignItems: 'center'
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
computed: {
|
|
62
|
+
preHeight () {
|
|
63
|
+
return (this.fontSize + 2) * (this.lineCount - 1)
|
|
64
|
+
},
|
|
65
|
+
lineHeight () {
|
|
66
|
+
return `${this.fontSize + 2}px`
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
mounted () {
|
|
70
|
+
// 由于在 element table 中,渲染计算时的宽度可能与实际展示时的宽度可能存在偏差,在此把宽度固定为组件挂载时获取到的宽度
|
|
71
|
+
this.$refs.contentEl.style.width = `${this.$refs.contentEl.offsetWidth}px`
|
|
72
|
+
// 处理长度为1的数据不用走截取逻辑减少计算
|
|
73
|
+
if (this.content.length === 1) {
|
|
74
|
+
this.restContent = this.content;
|
|
75
|
+
this.$refs.contentEl.remove();
|
|
76
|
+
this.lastLineHeight = (this.fontSize + 2);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
this.bsearch(this.content)
|
|
80
|
+
this.lastLineHeight = (this.fontSize + 2)
|
|
81
|
+
},
|
|
82
|
+
methods: {
|
|
83
|
+
bsearch (data, pre = 0) {
|
|
84
|
+
const len = data.length
|
|
85
|
+
const half = Math.floor((len - pre) / 2) + pre
|
|
86
|
+
if (len - pre <= 1) {
|
|
87
|
+
const restContent = pre === 0 ? this.content.slice(pre) : this.content.slice(pre + 1)
|
|
88
|
+
this.preContent = pre === 0 ? '' : data.slice(0, pre + 1)
|
|
89
|
+
if (!restContent) {
|
|
90
|
+
this.lastLineHeight = 0
|
|
91
|
+
this.$emit('update:isOverflow', false)
|
|
92
|
+
return false
|
|
93
|
+
}
|
|
94
|
+
this.restContent = restContent
|
|
95
|
+
this.$nextTick(() => {
|
|
96
|
+
this.$emit('update:isOverflow', this.$refs.lastLineEl.scrollWidth !== this.$refs.lastLineEl.offsetWidth)
|
|
97
|
+
})
|
|
98
|
+
return true
|
|
99
|
+
}
|
|
100
|
+
this.preContent = data.slice(0, half + 1)
|
|
101
|
+
this.$nextTick(() => {
|
|
102
|
+
const isEqual = this.$refs.contentEl.scrollHeight === this.preHeight
|
|
103
|
+
if (isEqual) {
|
|
104
|
+
this.alignItems = 'center'
|
|
105
|
+
return this.bsearch(data, half)
|
|
106
|
+
}
|
|
107
|
+
this.alignItems = 'flex-start'
|
|
108
|
+
return this.bsearch(data.slice(0, half), pre)
|
|
109
|
+
})
|
|
110
|
+
return true
|
|
111
|
+
},
|
|
112
|
+
isShowIconMethod() {
|
|
113
|
+
/**
|
|
114
|
+
* 1、isShowIcon--是否展示icon; length-- 所有传入数据总数量
|
|
115
|
+
* 2、this.overCountTip.index === this.overCountTip.length 当前列表展示个数(最后一个列)
|
|
116
|
+
* 3、length > this.overCountTip.length 满足总个数大于当前列表展示个数
|
|
117
|
+
**/
|
|
118
|
+
const { isShowIcon, length } = this.showIconObj;
|
|
119
|
+
return (isShowIcon && this.overCountTip.index === this.overCountTip.length && this.content.length && (length > this.overCountTip.length));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
</script>
|
|
124
|
+
|
|
125
|
+
<style lang="less">
|
|
126
|
+
.ellipsis {
|
|
127
|
+
width: 100%;
|
|
128
|
+
margin: 5px auto;
|
|
129
|
+
&__content {
|
|
130
|
+
width: 100%;
|
|
131
|
+
overflow: hidden;
|
|
132
|
+
display: flex;
|
|
133
|
+
}
|
|
134
|
+
&__last-line {
|
|
135
|
+
width: 100%;
|
|
136
|
+
overflow: hidden;
|
|
137
|
+
white-space: nowrap;
|
|
138
|
+
text-overflow: ellipsis;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
</style>
|