@king-design/intact 3.5.0-beta.0 → 3.5.1-beta.0
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/components/affix/index.md +1 -0
- package/components/affix/index.ts +2 -0
- package/components/affix/useStyle.ts +38 -35
- package/components/datepicker/basepicker.ts +3 -3
- package/components/dialog/styles.ts +2 -2
- package/components/dropdown/useKeyboard.ts +3 -0
- package/components/layout/styles.ts +1 -0
- package/components/select/base.ts +2 -0
- package/components/select/base.vdt +0 -2
- package/components/select/demos/group.md +1 -1
- package/components/select/demos/virtual.md +47 -0
- package/components/select/group.vdt +3 -2
- package/components/select/index.md +1 -0
- package/components/select/menu.vdt +5 -4
- package/components/select/select.vdt +1 -1
- package/components/select/useFilterable.ts +2 -2
- package/components/select/useInput.ts +6 -1
- package/components/table/demos/fixHeader.md +25 -5
- package/components/table/demos/virtual.md +105 -0
- package/components/table/index.md +1 -0
- package/components/table/index.spec.ts +2 -1
- package/components/table/row.ts +2 -1
- package/components/table/styles.ts +4 -0
- package/components/table/table.ts +6 -4
- package/components/table/table.vdt +15 -11
- package/components/treeSelect/index.ts +1 -1
- package/components/virtualList/container.ts +36 -0
- package/components/virtualList/container.vdt +30 -0
- package/components/virtualList/demos/basic.md +67 -0
- package/components/virtualList/demos/combined.md +57 -0
- package/components/virtualList/demos/delete.md +70 -0
- package/components/virtualList/index.md +19 -0
- package/components/virtualList/index.spec.ts +263 -0
- package/components/virtualList/index.ts +5 -0
- package/components/virtualList/phantom.ts +18 -0
- package/components/virtualList/phantom.vdt +28 -0
- package/components/virtualList/rows.ts +13 -0
- package/components/virtualList/rows.vdt +20 -0
- package/components/virtualList/styles.ts +29 -0
- package/components/virtualList/useRows.ts +24 -0
- package/components/virtualList/useVirtualRows.ts +145 -0
- package/components/virtualList/virtual.ts +19 -0
- package/components/virtualList/virtual.vdt +17 -0
- package/components/virtualList/wrapper.ts +17 -0
- package/components/virtualList/wrapper.vdt +24 -0
- package/es/components/affix/index.d.ts +1 -0
- package/es/components/affix/index.js +2 -1
- package/es/components/affix/useStyle.js +50 -47
- package/es/components/datepicker/basepicker.js +3 -3
- package/es/components/dialog/styles.js +2 -2
- package/es/components/dropdown/useKeyboard.js +3 -0
- package/es/components/input/index.spec.js +4 -2
- package/es/components/layout/styles.js +1 -1
- package/es/components/select/base.d.ts +1 -0
- package/es/components/select/base.js +2 -1
- package/es/components/select/base.vdt.js +2 -4
- package/es/components/select/group.vdt.js +8 -3
- package/es/components/select/menu.vdt.js +12 -3
- package/es/components/select/select.vdt.js +2 -1
- package/es/components/select/useFilterable.js +7 -5
- package/es/components/select/useInput.js +6 -2
- package/es/components/table/index.spec.js +7 -6
- package/es/components/table/styles.js +1 -1
- package/es/components/table/table.d.ts +1 -0
- package/es/components/table/table.js +3 -2
- package/es/components/table/table.vdt.js +126 -114
- package/es/components/treeSelect/index.js +4 -3
- package/es/components/virtualList/container.d.ts +10 -0
- package/es/components/virtualList/container.js +26 -0
- package/es/components/virtualList/container.vdt.js +39 -0
- package/es/components/virtualList/index.d.ts +5 -0
- package/es/components/virtualList/index.js +5 -0
- package/es/components/virtualList/index.spec.d.ts +1 -0
- package/es/components/virtualList/index.spec.js +372 -0
- package/es/components/virtualList/phantom.d.ts +9 -0
- package/es/components/virtualList/phantom.js +24 -0
- package/es/components/virtualList/phantom.vdt.js +33 -0
- package/es/components/virtualList/rows.d.ts +8 -0
- package/es/components/virtualList/rows.js +20 -0
- package/es/components/virtualList/rows.vdt.js +32 -0
- package/es/components/virtualList/styles.d.ts +13 -0
- package/es/components/virtualList/styles.js +34 -0
- package/es/components/virtualList/useRows.d.ts +2 -0
- package/es/components/virtualList/useRows.js +19 -0
- package/es/components/virtualList/useVirtualRows.d.ts +20 -0
- package/es/components/virtualList/useVirtualRows.js +120 -0
- package/es/components/virtualList/virtual.d.ts +8 -0
- package/es/components/virtualList/virtual.js +15 -0
- package/es/components/virtualList/virtual.vdt.js +26 -0
- package/es/components/virtualList/wrapper.d.ts +9 -0
- package/es/components/virtualList/wrapper.js +24 -0
- package/es/components/virtualList/wrapper.vdt.js +34 -0
- package/es/index.d.ts +3 -2
- package/es/index.js +3 -2
- package/es/site/data/components/select/demos/virtual/index.d.ts +11 -0
- package/es/site/data/components/select/demos/virtual/index.js +32 -0
- package/es/site/data/components/select/demos/virtual/react.d.ts +11 -0
- package/es/site/data/components/select/demos/virtual/react.js +54 -0
- package/es/site/data/components/table/demos/fixHeader/index.d.ts +6 -0
- package/es/site/data/components/table/demos/fixHeader/index.js +14 -0
- package/es/site/data/components/table/demos/fixHeader/react.d.ts +6 -0
- package/es/site/data/components/table/demos/fixHeader/react.js +28 -11
- package/es/site/data/components/table/demos/virtual/index.d.ts +13 -0
- package/es/site/data/components/table/demos/virtual/index.js +76 -0
- package/es/site/data/components/table/demos/virtual/react.d.ts +14 -0
- package/es/site/data/components/table/demos/virtual/react.js +114 -0
- package/es/site/data/components/virtualList/demos/basic/index.d.ts +12 -0
- package/es/site/data/components/virtualList/demos/basic/index.js +42 -0
- package/es/site/data/components/virtualList/demos/basic/react.d.ts +12 -0
- package/es/site/data/components/virtualList/demos/basic/react.js +67 -0
- package/es/site/data/components/virtualList/demos/combined/index.d.ts +11 -0
- package/es/site/data/components/virtualList/demos/combined/index.js +32 -0
- package/es/site/data/components/virtualList/demos/combined/react.d.ts +11 -0
- package/es/site/data/components/virtualList/demos/combined/react.js +50 -0
- package/es/site/data/components/virtualList/demos/delete/index.d.ts +13 -0
- package/es/site/data/components/virtualList/demos/delete/index.js +51 -0
- package/es/site/data/components/virtualList/demos/delete/react.d.ts +13 -0
- package/es/site/data/components/virtualList/demos/delete/react.js +75 -0
- package/es/site/data/components/virtualList/index.d.ts +57 -0
- package/es/site/data/components/virtualList/index.js +32 -0
- package/index.ts +3 -2
- package/package.json +2 -2
|
@@ -17,6 +17,7 @@ import {AllCheckedStatus} from './useChecked';
|
|
|
17
17
|
import {context as ResizableContext} from './useResizable';
|
|
18
18
|
import {context as FixedColumnsContext} from './useFixedColumns';
|
|
19
19
|
import {Pagination} from '../pagination';
|
|
20
|
+
import {VirtualListContainer, VirtualListWrapper, VirtualListRows, VirtualListPhantom} from '../virtualList';
|
|
20
21
|
|
|
21
22
|
const {
|
|
22
23
|
data, children, className, fixHeader,
|
|
@@ -25,7 +26,7 @@ const {
|
|
|
25
26
|
merge, childrenKey, indent, tooltipPosition,
|
|
26
27
|
tooltipContainer, showIndeterminate, resizable,
|
|
27
28
|
draggable, animation: _animation, hideHeader,
|
|
28
|
-
pagination, fixFooter, spreadArrowIndex
|
|
29
|
+
pagination, fixFooter, virtual, spreadArrowIndex
|
|
29
30
|
} = this.get();
|
|
30
31
|
const animation = !Array.isArray(_animation) ? [_animation, _animation] : _animation;
|
|
31
32
|
const {columns, cols, maxRows, maxCols} = this.columns.getData();
|
|
@@ -121,7 +122,7 @@ const {isSelected} = this.selected;
|
|
|
121
122
|
const {loopData, isSpreaded, toggleSpreadRow} = this.tree;
|
|
122
123
|
const {onRowDragStart, onRowDragOver, onRowDragEnd, draggingKey} = this.draggable;
|
|
123
124
|
const tbody = (
|
|
124
|
-
<tbody>
|
|
125
|
+
<VirtualListWrapper tagName="tbody">
|
|
125
126
|
{!hasData ?
|
|
126
127
|
<tr key="table-empty">
|
|
127
128
|
<td colspan={colCount} class={`${k}-table-empty`}>
|
|
@@ -138,6 +139,7 @@ const tbody = (
|
|
|
138
139
|
const key = allKeys[index];
|
|
139
140
|
const spreaded = isSpreaded(key);
|
|
140
141
|
const hasChildren = !!childrenKey && Array.isArray(value[childrenKey]);
|
|
142
|
+
|
|
141
143
|
const indentSize = indent ? indent * level : 0;
|
|
142
144
|
let row = <TableRow
|
|
143
145
|
key={key}
|
|
@@ -200,15 +202,15 @@ const tbody = (
|
|
|
200
202
|
);
|
|
201
203
|
}
|
|
202
204
|
|
|
203
|
-
|
|
205
|
+
return hidden || !spreaded;
|
|
204
206
|
});
|
|
205
207
|
|
|
206
|
-
return animation[0] ?
|
|
207
|
-
<TransitionGroup name="k-fade-in-left" move={!draggingKey.value}>{rows}</TransitionGroup> :
|
|
208
|
-
rows
|
|
208
|
+
return animation[0] && !virtual?
|
|
209
|
+
<TransitionGroup name="k-fade-in-left" move={!draggingKey.value}>{rows}</TransitionGroup> :
|
|
210
|
+
<VirtualListRows>{rows}</VirtualListRows>;
|
|
209
211
|
})()
|
|
210
212
|
}
|
|
211
|
-
</
|
|
213
|
+
</VirtualListWrapper>
|
|
212
214
|
);
|
|
213
215
|
|
|
214
216
|
let tfooter = null;
|
|
@@ -239,11 +241,13 @@ const {
|
|
|
239
241
|
} = this.pagination;
|
|
240
242
|
|
|
241
243
|
<div class={classNameObj} ref={elementRef}>
|
|
242
|
-
<
|
|
243
|
-
<
|
|
244
|
+
<VirtualListContainer class={`${k}-table-wrapper`} disabled={!virtual} style={style} ref={scrollRef}>
|
|
245
|
+
<VirtualListPhantom />
|
|
246
|
+
<Affix v-if={!isNull(stickHeader.value) || fixHeader}
|
|
244
247
|
top={stickHeader.value}
|
|
245
248
|
exclude={excludeStickHeader}
|
|
246
249
|
class={`${k}-table-affix-header`}
|
|
250
|
+
disabled={!!fixHeader}
|
|
247
251
|
>
|
|
248
252
|
<table ref={headRef} style={{width: tableWidthPx}}>
|
|
249
253
|
<template>{colgroup}</template>
|
|
@@ -252,11 +256,11 @@ const {
|
|
|
252
256
|
</Affix>
|
|
253
257
|
<table ref={tableRef} style={{width: tableWidthPx}}>
|
|
254
258
|
<template>{colgroup}</template>
|
|
255
|
-
<template v-if={isNull(stickHeader.value)}>{thead}</template>
|
|
259
|
+
<template v-if={isNull(stickHeader.value) && !fixHeader}>{thead}</template>
|
|
256
260
|
<template>{tbody}</template>
|
|
257
261
|
<template v-if={$blocks.footer}>{tfooter}</template>
|
|
258
262
|
</table>
|
|
259
|
-
</
|
|
263
|
+
</VirtualListContainer>
|
|
260
264
|
<Pagination v-if={pagination}
|
|
261
265
|
ref={paginationRef}
|
|
262
266
|
total={data ? data.length : 0}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Component, TypeDefs, findDomFromVNode } from 'intact';
|
|
2
|
+
import template from './container.vdt';
|
|
3
|
+
import { useConfigContext } from '../config';
|
|
4
|
+
import { useVirtualRows } from './useVirtualRows';
|
|
5
|
+
|
|
6
|
+
export interface VirtualListContainerProps {
|
|
7
|
+
disabled?: boolean
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const typeDefs: Required<TypeDefs<VirtualListContainerProps>> = {
|
|
11
|
+
disabled: Boolean,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export class VirtualListContainer extends Component<VirtualListContainerProps> {
|
|
15
|
+
static template = template;
|
|
16
|
+
static typeDefs = typeDefs;
|
|
17
|
+
|
|
18
|
+
private config = useConfigContext();
|
|
19
|
+
private virtualRows = useVirtualRows();
|
|
20
|
+
|
|
21
|
+
// TODO
|
|
22
|
+
// public scrollToIndex(index: number, behavior: ScrollBehavior = 'auto') {
|
|
23
|
+
// const { disabled } = this.get();
|
|
24
|
+
// if (disabled) return;
|
|
25
|
+
|
|
26
|
+
// let height = 0;
|
|
27
|
+
// for (let i = 0; i < index; i++) {
|
|
28
|
+
// height += this.virtualRows.getRowHeightByIndex(i);
|
|
29
|
+
// }
|
|
30
|
+
// const containerDom = findDomFromVNode(this.$lastInput!, true) as HTMLElement;
|
|
31
|
+
// containerDom.scrollTo({
|
|
32
|
+
// top: height,
|
|
33
|
+
// behavior,
|
|
34
|
+
// });
|
|
35
|
+
// }
|
|
36
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { addStyle, getRestProps } from '../utils';
|
|
2
|
+
import { makeContainerStyles } from './styles';
|
|
3
|
+
import { context as VirtualRowsContext } from './useVirtualRows';
|
|
4
|
+
|
|
5
|
+
const { children, className, disabled, ref } = this.get();
|
|
6
|
+
const { k } = this.config;
|
|
7
|
+
|
|
8
|
+
const { notifyRows, startIndex, length, getTotalHeight, translateY } = this.virtualRows;
|
|
9
|
+
|
|
10
|
+
const classNameObj = {
|
|
11
|
+
[`${k}-virtual`]: !disabled,
|
|
12
|
+
[`${k}-virtual-container`]: !disabled,
|
|
13
|
+
[makeContainerStyles(k)]: !disabled,
|
|
14
|
+
[className]: className,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
<VirtualRowsContext.Provider
|
|
18
|
+
value={{
|
|
19
|
+
disabled,
|
|
20
|
+
notifyRows,
|
|
21
|
+
getTotalHeight,
|
|
22
|
+
startIndex: startIndex.value,
|
|
23
|
+
length: length.value,
|
|
24
|
+
translateY: translateY.value,
|
|
25
|
+
}}
|
|
26
|
+
>
|
|
27
|
+
<div {...getRestProps(this)} class={classNameObj} ref={ref}>
|
|
28
|
+
{children}
|
|
29
|
+
</div>
|
|
30
|
+
</VirtualRowsContext.Provider>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 基本用法
|
|
3
|
+
order: 0
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
```vdt
|
|
7
|
+
import { VirtualList } from 'kpc';
|
|
8
|
+
|
|
9
|
+
<div>
|
|
10
|
+
<h3>1. 定高元素</h3>
|
|
11
|
+
<VirtualList style="height: 450px">
|
|
12
|
+
<div v-for={this.get('data')} class="fixed-height-item">
|
|
13
|
+
{$value.label}
|
|
14
|
+
</div>
|
|
15
|
+
</VirtualList>
|
|
16
|
+
|
|
17
|
+
<h3>2. 不定高元素</h3>
|
|
18
|
+
<VirtualList style="width: 200px; height: 450px;">
|
|
19
|
+
<div v-for={this.get('variableHeightData')} class="variable-height-item">
|
|
20
|
+
{$value.label}
|
|
21
|
+
</div>
|
|
22
|
+
</VirtualList>
|
|
23
|
+
</div>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
```styl
|
|
27
|
+
.fixed-height-item
|
|
28
|
+
height 30px
|
|
29
|
+
border-bottom 1px solid #eee
|
|
30
|
+
padding 5px
|
|
31
|
+
.variable-height-item
|
|
32
|
+
min-height 20px
|
|
33
|
+
border-bottom 1px solid #eee
|
|
34
|
+
padding 5px
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
interface Props {
|
|
39
|
+
data: any[]
|
|
40
|
+
variableHeightData: any[]
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export default class extends Component {
|
|
44
|
+
static template = template;
|
|
45
|
+
|
|
46
|
+
static defaults() {
|
|
47
|
+
return {
|
|
48
|
+
data: [],
|
|
49
|
+
variableHeightData: [],
|
|
50
|
+
} as Props;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
init() {
|
|
54
|
+
const arr = [];
|
|
55
|
+
const variableHeightData = [];
|
|
56
|
+
for (let index = 0; index < 10000; index++) {
|
|
57
|
+
arr.push({
|
|
58
|
+
value: index,
|
|
59
|
+
label: `测试${index}`
|
|
60
|
+
});
|
|
61
|
+
const repeatPart = '行内容'.repeat(Math.floor(Math.random() * 5) + 1);
|
|
62
|
+
variableHeightData.push({ value: index, label: `不定高度项 ${index}\n${repeatPart}` });
|
|
63
|
+
}
|
|
64
|
+
this.set({data: arr, variableHeightData});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 组合使用
|
|
3
|
+
order: 1
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
在一些复杂场景中,可以通过`VirtualListContainer`、`VirtualListWrapper`等子组件组合使用, 也可通过`tagName`属性指定自定义标签
|
|
7
|
+
|
|
8
|
+
```vdt
|
|
9
|
+
import { VirtualListContainer, VirtualListWrapper, VirtualListPhantom, VirtualListRows } from 'kpc';
|
|
10
|
+
|
|
11
|
+
<div style="height: 460px">
|
|
12
|
+
<VirtualListContainer >
|
|
13
|
+
<VirtualListPhantom />
|
|
14
|
+
<VirtualListWrapper tagName="ul">
|
|
15
|
+
<VirtualListRows>
|
|
16
|
+
<li v-for={this.get('data')} class="fixed-height-item">
|
|
17
|
+
{$value.label}
|
|
18
|
+
</li>
|
|
19
|
+
</VirtualListRows>
|
|
20
|
+
</VirtualListWrapper>
|
|
21
|
+
</VirtualListContainer>
|
|
22
|
+
</div>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```styl
|
|
26
|
+
.fixed-height-item
|
|
27
|
+
height 30px
|
|
28
|
+
border-bottom 1px solid #eee
|
|
29
|
+
padding 5px
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
interface Props {
|
|
34
|
+
data: any[]
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default class extends Component {
|
|
38
|
+
static template = template;
|
|
39
|
+
|
|
40
|
+
static defaults() {
|
|
41
|
+
return {
|
|
42
|
+
data: [],
|
|
43
|
+
} as Props;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
init() {
|
|
47
|
+
const arr = [];
|
|
48
|
+
for (let index = 0; index < 10000; index++) {
|
|
49
|
+
arr.push({
|
|
50
|
+
value: index,
|
|
51
|
+
label: `测试${index}`
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
this.set({data: arr});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 动态删除元素
|
|
3
|
+
order: 2
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
```vdt
|
|
7
|
+
import { VirtualList, Button } from 'kpc';
|
|
8
|
+
|
|
9
|
+
<div>
|
|
10
|
+
<Button ev-click={this.removeItems}>删除前5项</Button>
|
|
11
|
+
<Button ev-click={this.removeLastItems}>删除后5项</Button>
|
|
12
|
+
<VirtualList style="height: 450px">
|
|
13
|
+
<div v-for={this.get('data')} class="fixed-height-item">
|
|
14
|
+
{$value.label}
|
|
15
|
+
</div>
|
|
16
|
+
</VirtualList>
|
|
17
|
+
</div>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```styl
|
|
21
|
+
.fixed-height-item
|
|
22
|
+
height 30px
|
|
23
|
+
border-bottom 1px solid #eee
|
|
24
|
+
padding 5px
|
|
25
|
+
.k-btn
|
|
26
|
+
margin-bottom 10px
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
import {bind} from 'kpc/components/utils';
|
|
31
|
+
interface Props {
|
|
32
|
+
data: any[]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default class extends Component<Props> {
|
|
36
|
+
static template = template;
|
|
37
|
+
|
|
38
|
+
static defaults() {
|
|
39
|
+
return {
|
|
40
|
+
data: [],
|
|
41
|
+
} as Props
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
init() {
|
|
45
|
+
const newData = [];
|
|
46
|
+
const variableHeightData = [];
|
|
47
|
+
for (let index = 0; index < 10000; index++) {
|
|
48
|
+
newData.push({
|
|
49
|
+
value: index,
|
|
50
|
+
label: `测试${index}`
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
this.set({data: newData});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@bind
|
|
57
|
+
removeItems() {
|
|
58
|
+
const data = this.get('data').slice();
|
|
59
|
+
data.splice(0, 5);
|
|
60
|
+
this.set('data', data);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@bind
|
|
64
|
+
removeLastItems() {
|
|
65
|
+
const data = this.get('data').slice();
|
|
66
|
+
data.splice(data.length - 5);
|
|
67
|
+
this.set('data', data);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 虚拟列表
|
|
3
|
+
category: 组件
|
|
4
|
+
order: 99
|
|
5
|
+
sidebar: doc
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# 属性
|
|
9
|
+
|
|
10
|
+
| 属性 | 说明 | 类型 | 默认值 |
|
|
11
|
+
| --- | --- | --- | --- |
|
|
12
|
+
| disabled | 是否禁用虚拟化 | `boolean` | `false` |
|
|
13
|
+
|
|
14
|
+
<!-- # 方法 -->
|
|
15
|
+
|
|
16
|
+
<!-- | 方法名 | 说明 | 参数 | -->
|
|
17
|
+
<!-- | --- | --- | --- | -->
|
|
18
|
+
<!-- | scrollToIndex | 滚动到指定索引位置 | `(index: number, behavior?: 'auto' \| 'smooth') => void` | -->
|
|
19
|
+
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import {mount, unmount, dispatchEvent, getElement, wait} from '../../test/utils';
|
|
2
|
+
import {VirtualList, VirtualListContainer, VirtualListWrapper, VirtualListPhantom} from './';
|
|
3
|
+
import {Component} from 'intact';
|
|
4
|
+
import BasicDemo from '~/components/virtualList/demos/basic';
|
|
5
|
+
import CombinedDemo from '~/components/virtualList/demos/combined';
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
describe('VirtualList', () => {
|
|
9
|
+
afterEach(() => unmount());
|
|
10
|
+
|
|
11
|
+
it('should render virtual list correctly', async () => {
|
|
12
|
+
const [instance, element] = mount(BasicDemo);
|
|
13
|
+
|
|
14
|
+
// check basic structure
|
|
15
|
+
const container = element.querySelector('.k-virtual-container')!;
|
|
16
|
+
expect(container.outerHTML).to.matchSnapshot();
|
|
17
|
+
|
|
18
|
+
const wrapper = element.querySelector('.k-virtual-wrapper')!;
|
|
19
|
+
expect(wrapper).to.exist;
|
|
20
|
+
|
|
21
|
+
// check render items is less than total
|
|
22
|
+
const items = wrapper.children;
|
|
23
|
+
expect(items.length).to.be.lessThan(100);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should handle scroll correctly', async () => {
|
|
27
|
+
const [instance, element] = mount(BasicDemo);
|
|
28
|
+
|
|
29
|
+
const container = element.querySelector('.k-virtual-container')!;
|
|
30
|
+
const wrapper = element.querySelector('.k-virtual-wrapper')!;
|
|
31
|
+
await wait(50);
|
|
32
|
+
container.scrollTop = 400;
|
|
33
|
+
await wait(50);
|
|
34
|
+
|
|
35
|
+
// check content is updated
|
|
36
|
+
const currentFirstItem = wrapper.firstElementChild;
|
|
37
|
+
expect(currentFirstItem!.textContent).to.not.equal('测试0');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
it('should update total height when data changes', async () => {
|
|
42
|
+
const [instance, element] = mount(BasicDemo);
|
|
43
|
+
const [, container2] = element.querySelectorAll<HTMLElement>('.k-virtual-container');
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
const [, phantom2] = element.querySelectorAll<HTMLElement>('.k-virtual-phantom')!;
|
|
47
|
+
const initialHeight = phantom2.style.height;
|
|
48
|
+
await wait(50);
|
|
49
|
+
container2.scrollTop = 800;
|
|
50
|
+
await wait(50);
|
|
51
|
+
|
|
52
|
+
// check phantom height is updated
|
|
53
|
+
expect(phantom2.style.height).to.not.equal(initialHeight);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('should work with custom container and wrapper', async () => {
|
|
57
|
+
const [instance, element] = mount(CombinedDemo);
|
|
58
|
+
await wait();
|
|
59
|
+
|
|
60
|
+
const container = element.querySelector('.k-virtual-container')!;
|
|
61
|
+
const wrapper = element.querySelector('.k-virtual-wrapper')!;
|
|
62
|
+
|
|
63
|
+
expect(container.outerHTML).to.matchSnapshot();
|
|
64
|
+
// check wrapper tag name
|
|
65
|
+
expect(wrapper.tagName.toLowerCase()).to.equal('ul');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should handle dynamic data changes correctly', async () => {
|
|
69
|
+
class Demo extends Component<{list: number[]}> {
|
|
70
|
+
static template = `
|
|
71
|
+
const VirtualList = this.VirtualList;
|
|
72
|
+
<VirtualList style="height: 300px">
|
|
73
|
+
<div v-for={this.get('list')} key={$value}>Item {$value}</div>
|
|
74
|
+
</VirtualList>
|
|
75
|
+
`;
|
|
76
|
+
|
|
77
|
+
static defaults() {
|
|
78
|
+
return {
|
|
79
|
+
list: Array.from({length: 100}, (_, i) => i)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
private VirtualList = VirtualList;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const [instance] = mount(Demo);
|
|
86
|
+
await wait();
|
|
87
|
+
|
|
88
|
+
const container = getElement('.k-virtual-container')!;
|
|
89
|
+
const wrapper = getElement('.k-virtual-wrapper')!;
|
|
90
|
+
|
|
91
|
+
instance.set('list', instance.get('list')!.filter(i => i % 2 === 0));
|
|
92
|
+
await wait();
|
|
93
|
+
|
|
94
|
+
// check deleted render
|
|
95
|
+
expect(wrapper.children.length).to.be.lessThan(100);
|
|
96
|
+
expect(wrapper.firstElementChild!.textContent).to.equal('Item 0');
|
|
97
|
+
|
|
98
|
+
container.scrollTop = 300;
|
|
99
|
+
await wait(50);
|
|
100
|
+
|
|
101
|
+
// check scroll render
|
|
102
|
+
const middleContent = wrapper.firstElementChild!.textContent;
|
|
103
|
+
expect(middleContent).to.not.equal('Item 0');
|
|
104
|
+
|
|
105
|
+
const newList = [...instance.get('list'), ...Array.from({length: 20}, (_, i) => i + 200)];
|
|
106
|
+
instance.set('list', newList);
|
|
107
|
+
await wait(50);
|
|
108
|
+
|
|
109
|
+
// check add render position not change
|
|
110
|
+
expect(wrapper.firstElementChild!.textContent).to.equal(middleContent);
|
|
111
|
+
|
|
112
|
+
const prevScrollTop = container.scrollTop;
|
|
113
|
+
container.scrollTop = prevScrollTop + 200;
|
|
114
|
+
await wait(50);
|
|
115
|
+
|
|
116
|
+
// check scroll to new content
|
|
117
|
+
expect(wrapper.firstElementChild!.textContent).to.not.equal(middleContent);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should handle visible area data changes', async () => {
|
|
121
|
+
class Demo extends Component<{list: number[]}> {
|
|
122
|
+
static template = `
|
|
123
|
+
const VirtualList = this.VirtualList;
|
|
124
|
+
<VirtualList style="height: 300px">
|
|
125
|
+
<div v-for={this.get('list')} key={$value}>Item {$value}</div>
|
|
126
|
+
</VirtualList>
|
|
127
|
+
`;
|
|
128
|
+
static defaults() {
|
|
129
|
+
return {
|
|
130
|
+
list: Array.from({length: 100}, (_, i) => i)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
private VirtualList = VirtualList;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const [instance, element] = mount(Demo);
|
|
137
|
+
await wait();
|
|
138
|
+
|
|
139
|
+
const container = getElement('.k-virtual-container')!;
|
|
140
|
+
const wrapper = getElement('.k-virtual-wrapper')!;
|
|
141
|
+
|
|
142
|
+
container.scrollTop = 300;
|
|
143
|
+
await wait(50);
|
|
144
|
+
|
|
145
|
+
const visibleFirstItem = wrapper.firstElementChild!.textContent;
|
|
146
|
+
const currentList = instance.get('list');
|
|
147
|
+
|
|
148
|
+
// delete visible items
|
|
149
|
+
const visibleIndex = parseInt(visibleFirstItem!.replace('Item ', ''));
|
|
150
|
+
const newList = currentList.filter(i => i !== visibleIndex && i !== visibleIndex + 1);
|
|
151
|
+
instance.set('list', newList);
|
|
152
|
+
await wait();
|
|
153
|
+
|
|
154
|
+
// check deleted render and position
|
|
155
|
+
expect(wrapper.firstElementChild!.textContent).to.not.equal(visibleFirstItem);
|
|
156
|
+
expect(wrapper.children.length).to.be.greaterThan(0);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('should clean up height cache when items are deleted', async () => {
|
|
160
|
+
class Demo extends Component<{list: number[]}> {
|
|
161
|
+
static template = `
|
|
162
|
+
const VirtualList = this.VirtualList;
|
|
163
|
+
<VirtualList style="height: 300px">
|
|
164
|
+
<div v-for={this.get('list')} key={$value} style="height: 30px">Item {$value}</div>
|
|
165
|
+
</VirtualList>
|
|
166
|
+
`;
|
|
167
|
+
static defaults() {
|
|
168
|
+
return {
|
|
169
|
+
list: Array.from({length: 100}, (_, i) => i)
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
private VirtualList = VirtualList;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const [instance, element] = mount(Demo);
|
|
176
|
+
await wait();
|
|
177
|
+
|
|
178
|
+
const container = getElement('.k-virtual-container')!;
|
|
179
|
+
|
|
180
|
+
// first cache some height
|
|
181
|
+
container.scrollTop = 300;
|
|
182
|
+
await wait(50);
|
|
183
|
+
|
|
184
|
+
// get first visible item
|
|
185
|
+
const wrapper = getElement('.k-virtual-wrapper')!;
|
|
186
|
+
const firstVisibleItem = wrapper.firstElementChild!;
|
|
187
|
+
const firstVisibleIndex = parseInt(firstVisibleItem.textContent!.replace('Item ', ''));
|
|
188
|
+
|
|
189
|
+
// delete visible items
|
|
190
|
+
const currentList = instance.get('list');
|
|
191
|
+
const newList = currentList.filter(i => i > firstVisibleIndex + 5);
|
|
192
|
+
instance.set('list', newList);
|
|
193
|
+
await wait(50);
|
|
194
|
+
|
|
195
|
+
// check scroll position is adjusted
|
|
196
|
+
const newFirstItem = wrapper.firstElementChild!;
|
|
197
|
+
expect(parseInt(newFirstItem.textContent!.replace('Item ', ''))).to.be.greaterThan(firstVisibleIndex);
|
|
198
|
+
|
|
199
|
+
// scroll again to check render is normal
|
|
200
|
+
container.scrollTop += 100;
|
|
201
|
+
await wait(50);
|
|
202
|
+
|
|
203
|
+
// check new render position is correct
|
|
204
|
+
const afterScrollItem = wrapper.firstElementChild!;
|
|
205
|
+
expect(afterScrollItem.textContent).to.not.equal(newFirstItem.textContent);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it('should update total height when deleting last items', async () => {
|
|
209
|
+
class Demo extends Component<{list: number[]}> {
|
|
210
|
+
static template = `
|
|
211
|
+
const VirtualList = this.VirtualList;
|
|
212
|
+
<VirtualList style="height: 300px">
|
|
213
|
+
<div v-for={this.get('list')} key={$value} style="height: 30px">Item {$value}</div>
|
|
214
|
+
</VirtualList>
|
|
215
|
+
`;
|
|
216
|
+
static defaults() {
|
|
217
|
+
return {
|
|
218
|
+
list: Array.from({length: 100}, (_, i) => i)
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
private VirtualList = VirtualList;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const [instance, element] = mount(Demo);
|
|
225
|
+
await wait();
|
|
226
|
+
|
|
227
|
+
const container = getElement('.k-virtual-container')!;
|
|
228
|
+
const phantom = getElement('.k-virtual-phantom')!;
|
|
229
|
+
|
|
230
|
+
// record initial total height
|
|
231
|
+
const initialHeight = parseInt(phantom.style.height);
|
|
232
|
+
|
|
233
|
+
// scroll to cache height
|
|
234
|
+
container.scrollTop = initialHeight;
|
|
235
|
+
await wait(50);
|
|
236
|
+
|
|
237
|
+
const wrapper = getElement('.k-virtual-wrapper')!;
|
|
238
|
+
const lastVisibleItem = wrapper.lastElementChild!;
|
|
239
|
+
const lastVisibleIndex = parseInt(lastVisibleItem.textContent!.replace('Item ', ''));
|
|
240
|
+
|
|
241
|
+
// delete last 5 items
|
|
242
|
+
const currentList = instance.get('list');
|
|
243
|
+
const newList = currentList.slice(0, -5);
|
|
244
|
+
instance.set('list', newList);
|
|
245
|
+
await wait(50);
|
|
246
|
+
|
|
247
|
+
// check total height is updated
|
|
248
|
+
const finalHeight = parseInt(phantom.style.height);
|
|
249
|
+
expect(finalHeight).to.equal(initialHeight - 5 * 30);
|
|
250
|
+
|
|
251
|
+
// check new last item is at bottom
|
|
252
|
+
const newLastItem = wrapper.lastElementChild!;
|
|
253
|
+
const newLastIndex = parseInt(newLastItem.textContent!.replace('Item ', ''));
|
|
254
|
+
expect(newLastIndex).to.equal(94);
|
|
255
|
+
|
|
256
|
+
// check new last item is at bottom
|
|
257
|
+
const containerRect = container.getBoundingClientRect();
|
|
258
|
+
const lastItemRect = newLastItem.getBoundingClientRect();
|
|
259
|
+
const isAtBottom = Math.abs((containerRect.bottom - lastItemRect.bottom)) <= 1;
|
|
260
|
+
expect(isAtBottom).to.be.true;
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Component, TypeDefs } from 'intact';
|
|
2
|
+
import template from './phantom.vdt';
|
|
3
|
+
import { useConfigContext } from '../config';
|
|
4
|
+
|
|
5
|
+
export interface VirtualListPhantomProps {
|
|
6
|
+
tagName?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const typeDefs: Required<TypeDefs<VirtualListPhantomProps>> = {
|
|
10
|
+
tagName: String,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export class VirtualListPhantom extends Component<VirtualListPhantomProps> {
|
|
14
|
+
static template = template;
|
|
15
|
+
static typeDefs = typeDefs;
|
|
16
|
+
|
|
17
|
+
private config = useConfigContext();
|
|
18
|
+
}
|