Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Virtual #1050

Merged
merged 22 commits into from
Jan 9, 2025
Merged

Virtual #1050

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading