Skip to content

Commit

Permalink
Merge pull request #1050 from ksc-fe/virtual
Browse files Browse the repository at this point in the history
Virtual
  • Loading branch information
warrior-bing authored Jan 9, 2025
2 parents 20d584f + 1a2aa9a commit a5145b5
Show file tree
Hide file tree
Showing 61 changed files with 1,612 additions and 394 deletions.
1 change: 1 addition & 0 deletions components/affix/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ sidebar: doc
| bottom | 指定元素固定距离底部的位置 | `number` | `undefined` |
| shouldFix | 自定义元素固定规则 | `Function` | `undefined` |
| exclude | 排除某些固定的情况 | `Function` | `undefined` |
| disabled | 是否禁用 | `Boolean` | `false` |

# 事件

Expand Down
2 changes: 2 additions & 0 deletions components/affix/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export interface AffixProps {
bottom?: number
exclude?: (data: ExcludeParam) => boolean
shouldFix?: (data: ShouldFixParam) => boolean
disabled?: boolean
}

export interface AffixEvents {
Expand All @@ -34,6 +35,7 @@ const typeDefs: Required<TypeDefs<AffixProps>> = {
bottom: Number,
exclude: Function,
shouldFix: Function,
disabled: Boolean,
};

export class Affix extends Component<AffixProps, AffixEvents> {
Expand Down
73 changes: 38 additions & 35 deletions components/affix/useStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,44 +12,47 @@ export function useStyle(elementRef: RefObject<HTMLElement>) {
let ro: ResizeObserver | null = null;

function genStyle() {
let {top: offsetTop, bottom: offsetBottom, exclude, shouldFix} = instance.get();
const {top, bottom, width, height} = elementRef.value!.getBoundingClientRect();

const setStyle = (styles: Record<string, string>) => {
if (!exclude || exclude && !exclude({
offsetTop, offsetBottom, top, bottom, width, height
})) {
style.set({
position: 'fixed',
width: `${width}px`,
...styles,
});
containerStyle.set({
height: `${height}px`,
});
} else {
resetStyle();
}
};
let {top: offsetTop, bottom: offsetBottom, exclude, shouldFix, disabled} = instance.get();

if (isNullOrUndefined(offsetTop) && isNullOrUndefined(offsetBottom)) {
offsetTop = 0;
}
if (!disabled) {
const {top, bottom, width, height} = elementRef.value!.getBoundingClientRect();

const setStyle = (styles: Record<string, string>) => {
if (!exclude || exclude && !exclude({
offsetTop, offsetBottom, top, bottom, width, height
})) {
style.set({
position: 'fixed',
width: `${width}px`,
...styles,
});
containerStyle.set({
height: `${height}px`,
});
} else {
resetStyle();
}
};

if (!isNullOrUndefined(offsetTop)) {
if (
shouldFix && shouldFix({offsetTop, offsetBottom}) ||
!shouldFix && top < offsetTop
) {
return setStyle({top: `${offsetTop}px`});
if (isNullOrUndefined(offsetTop) && isNullOrUndefined(offsetBottom)) {
offsetTop = 0;
}
} else {
const viewportHeight = document.documentElement.clientHeight;
if (
shouldFix && shouldFix({offsetTop, offsetBottom, viewportHeight}) ||
!shouldFix && !isNullOrUndefined(offsetBottom) && viewportHeight - bottom <= offsetBottom
) {
return setStyle({bottom: `${offsetBottom}px`});

if (!isNullOrUndefined(offsetTop)) {
if (
shouldFix && shouldFix({offsetTop, offsetBottom}) ||
!shouldFix && top < offsetTop
) {
return setStyle({top: `${offsetTop}px`});
}
} else {
const viewportHeight = document.documentElement.clientHeight;
if (
shouldFix && shouldFix({offsetTop, offsetBottom, viewportHeight}) ||
!shouldFix && !isNullOrUndefined(offsetBottom) && viewportHeight - bottom <= offsetBottom
) {
return setStyle({bottom: `${offsetBottom}px`});
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions components/dialog/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ const defaults = {
padding: `0 24px`,
bodyMarginTop: `-25px`,
tipIconMarginBottom: '10px',
tipIconFontSize: '24px',
tipIconLineHeight: '24px',
tipIconFontSize: '40px',
tipIconLineHeight: '40px',

// with title
titleFontWeight: '500',
Expand Down
3 changes: 3 additions & 0 deletions components/dropdown/useKeyboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ export function useMenuKeyboard() {
const item = items[focusIndex];

if (focusIndex > -1 && item) {
// TODO(find bug)
itemEvents.get(item)!.onFocusout();
focusIndex = -1;
}
Expand Down Expand Up @@ -203,6 +204,8 @@ export function useItemKeyboard(itemEvents: Omit<ItemEvents, 'onFocusin' | 'onFo
onMouseLeave(e: MouseEvent) {
instance.trigger('mouseleave', e);
keyboard.reset();
// If it is a virtual item, it needs to be reset manually because the DOM is reused.
isFocus.set(false);
},

isFocus,
Expand Down
2 changes: 2 additions & 0 deletions components/select/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export interface BaseSelectProps<V, Multipe extends boolean = boolean, Attach =
flat?: boolean
nowrap?: boolean
draggable?: boolean
virtual?: boolean
}

export interface BaseSelectEvents {
Expand Down Expand Up @@ -78,6 +79,7 @@ const typeDefs: Required<TypeDefs<BaseSelectProps<any>>> = {
flat: Boolean,
nowrap: Boolean,
draggable: Boolean,
virtual: Boolean,
};

const defaults = (): Partial<BaseSelectProps<any>> => ({
Expand Down
2 changes: 1 addition & 1 deletion components/select/demos/group.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {Select, Option, OptionGroup} from 'kpc';
<Option value="Tuesday">星期二</Option>
<Option value="Wednesday">星期三</Option>
<Option value="Thursday">星期四</Option>
<Option value="Friday">星期五</Option>
<Option value="Friday">星期五</Option>
</OptionGroup>
<OptionGroup>
<b:label><i class="ion-wineglass"></i>休息日</b:label>
Expand Down
47 changes: 47 additions & 0 deletions components/select/demos/virtual.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
title: 虚拟列表
order: 14
---

`virtual`属性开启虚拟列表

```vdt
import {Select, Option} from 'kpc';
<div>
<Select v-model="day" virtual>
<Option v-for={this.get('data')} value={$value.value}>
{$value.label}
</Option>
</Select>
</div>
```

```ts
interface Props {
day?: string | null
data: any[]
}

export default class extends Component {
static template = template;

static defaults() {
return {
day: null,
data: []
} as Props;
}

init() {
const arr = [];
for (let index = 0; index < 10000; index++) {
arr.push({
value: index,
label: `测试${index}`
});
}
this.set({data: arr});
}
}
```
5 changes: 3 additions & 2 deletions components/select/group.vdt
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import {makeGroupStyles} from './styles';
import {getRestProps} from '../utils';
import { VirtualList } from '../virtualList';

const {children, label, className} = this.get();
const {card} = this.select.get();
const {card, virtual} = this.select.get();
const { k } = this.config;

const classNameObj = {
Expand All @@ -15,5 +16,5 @@ const classNameObj = {
<div class={`${k}-select-group-label`} v-if={!card}>
<b:label>{label}</b:label>
</div>
{children}
<VirtualList disabled={!virtual}>{children}</VirtualList>
</div>
1 change: 1 addition & 0 deletions components/select/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ sidebar: doc
| position | 菜单弹出的位置,默认与触发器左侧对齐向下偏移`8px`的地方 | `Position` &#124; `"left"` &#124; `"bottom"` &#124; `"right"` &#124; `"top"` | `{my: 'left top+8', 'left bottom'}` |
| flat | 是否展示扁平样式 | `boolean` | `false` |
| draggable | 多选值是否支持拖动排序 | `boolean` | `false` |
| virtual | 是否开启虚拟列表 | `boolean` | `false` |

```ts
type Position = {
Expand Down
9 changes: 5 additions & 4 deletions components/select/menu.vdt
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import {Button} from '../button';
import {Icon} from '../icon';
import {context} from './useSearchable';
import {Tabs, Tab} from '../tabs';
import { VirtualList } from '../virtualList';

let {children, className} = this.get();
const {card, searchable, multiple} = this.select.get();
const {card, searchable, multiple, virtual} = this.select.get();
const { k } = this.config;

const classNameObj = {
Expand All @@ -38,14 +39,14 @@ if (card) {
{group}
</template>
);
}

if (isEmptyChildren(children)) {
} else if (isEmptyChildren(children)) {
children = (
<div v-else class={`${k}-select-empty`}>
{_$('无数据')}
</div>
);
} else {
children = <VirtualList style={{maxHeight: '200px'}} disabled={!virtual}>{children}</VirtualList>
}

if (searchable) {
Expand Down
2 changes: 1 addition & 1 deletion components/select/select.vdt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {SelectMenu} from './menu';
import {isEmptyChildren} from '../utils';

const {className, children, autoDisableArrow, disabled, multiple, value} = this.get();
const {className, children, autoDisableArrow, disabled, multiple, value, virtual} = this.get();
const {getCreatedVNode, filter} = this.filterable;
const options = filter(children);
const allShowedValues = this.getAllShowedValues(options);
Expand Down
30 changes: 25 additions & 5 deletions components/table/demos/fixHeader.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,39 @@ import {Table, TableColumn} from 'kpc';
>
<TableColumn key="a" title="100px" />
</Table>
<Table
data={[{a: '表头固定啦'}, {a: '下拉'}, {a: 'yeah!'}]}
fixHeader="100"
>
<TableColumn key="a" title="100px" />
<Table data={this.get('data')} fixHeader="300">
<TableColumn title="Name" key="name" fixed="left" />
<TableColumn title="IP" key="ip" />
</Table>
</div>
```

```styl
.wrapper
display flex
align-items flex-start
.k-table
margin-left: 20px
flex: 1
```

```ts
import {range, bind} from 'kpc/components/utils';

const data = range(1, 100).map(item => {
return {
name: 'name ' + item,
ip: '127.0.0.' + item
};
});

export default class extends Component {
static template = template;

static defaults() {
return {
data: data
}
}
}
```
Loading

0 comments on commit a5145b5

Please sign in to comment.