-
{content}
- {propsActionContent &&
{propsActionContent}}
+
+
+
{content}
+ {propsActionContent &&
{propsActionContent}}
);
diff --git a/src/list/list.en-US.md b/src/list/list.en-US.md
index 019660404..49e003de7 100644
--- a/src/list/list.en-US.md
+++ b/src/list/list.en-US.md
@@ -1,6 +1,7 @@
:: BASE_DOC ::
## API
+
### List Props
name | type | default | description | required
@@ -8,8 +9,9 @@ name | type | default | description | required
asyncLoading | String / Slot / Function | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N
footer | String / Slot / Function | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N
header | String / Slot / Function | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N
-layout | String | horizontal | options:horizontal/vertical | N
-size | String | medium | options:small/medium/large | N
+layout | String | horizontal | options: horizontal/vertical | N
+scroll | Object | - | lazy load and virtual scroll。Typescript:`TScroll`。[see more ts definition](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N
+size | String | medium | options: small/medium/large | N
split | Boolean | false | \- | N
stripe | Boolean | false | \- | N
onLoadMore | Function | | Typescript:`(options: { e: MouseEvent }) => void`
| N
@@ -22,6 +24,7 @@ name | params | description
load-more | `(options: { e: MouseEvent })` | \-
scroll | `(options: { e: Event \| WheelEvent; scrollTop: number; scrollBottom: number })` | \-
+
### ListItem Props
name | type | default | description | required
@@ -29,13 +32,7 @@ name | type | default | description | required
action | String / Slot / Function | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N
content | String / Slot / Function | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N
default | String / Slot / Function | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N
-onClick | Function | | Typescript:`(context: { e: MouseEvent }) => void`
| N
-
-### ListItem Events
-name | params | description
--- | -- | --
-click | `(context: { e: MouseEvent })` | \-
### ListItemMeta Props
diff --git a/src/list/list.md b/src/list/list.md
index c3614f8fa..13782b1c9 100644
--- a/src/list/list.md
+++ b/src/list/list.md
@@ -1,38 +1,16 @@
:: BASE_DOC ::
-### 斑马纹的列表
-
-当列表内容较多时,可以使用斑马纹样式,便于用户获取信息。
-
-{{ stripe }}
-
-### 异步加载的列表
-
-当数据需要通过二次请求加载展示时,可以通过`asyncLoading`来处理相关的逻辑。
-
-{{ loading }}
-
-### 带头部及尾部的列表
-
-当列表需要展示头部或尾部信息时,可以通过`header`或`footer`来配置。
-
-{{ header-footer }}
-
-### 带滚动事件的列表
-
-当列表较长时,可以配置滚动条及事件来进行滚动处理
-
-{{ scroll }}
-
## API
+
### List Props
-名称 | 类型 | 默认值 | 说明 | 必传
+名称 | 类型 | 默认值 | 描述 | 必传
-- | -- | -- | -- | --
asyncLoading | String / Slot / Function | - | 自定义加载中。值为空不显示加载中,值为 'loading' 显示加载中状态,值为 'load-more' 显示加载更多状态。值类型为函数,则表示自定义加载状态呈现内容。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N
footer | String / Slot / Function | - | 底部。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N
header | String / Slot / Function | - | 头部。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N
layout | String | horizontal | 排列方式(待设计稿输出)。可选项:horizontal/vertical | N
+scroll | Object | - | 懒加载和虚拟滚动。为保证组件收益最大化,当数据量小于阈值 `scroll.threshold` 时,无论虚拟滚动的配置是否存在,组件内部都不会开启虚拟滚动,`scroll.threshold` 默认为 `100`。TS 类型:`TScroll`。[通用类型定义](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N
size | String | medium | 尺寸。可选项:small/medium/large | N
split | Boolean | false | 是否展示分割线 | N
stripe | Boolean | false | 是否展示斑马纹 | N
@@ -46,25 +24,19 @@ onScroll | Function | | TS 类型:`(options: { e: Event \| WheelEvent; scroll
load-more | `(options: { e: MouseEvent })` | 点击加载更多时触发
scroll | `(options: { e: Event \| WheelEvent; scrollTop: number; scrollBottom: number })` | 列表滚动时触发,scrollTop 表示顶部滚动距离,scrollBottom 表示底部滚动距离
+
### ListItem Props
-名称 | 类型 | 默认值 | 说明 | 必传
+名称 | 类型 | 默认值 | 描述 | 必传
-- | -- | -- | -- | --
action | String / Slot / Function | - | 操作栏。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N
content | String / Slot / Function | - | 内容。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N
default | String / Slot / Function | - | 内容,同 content。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N
-onClick | Function | | TS 类型:`(context: { e: MouseEvent }) => void`
点击时触发 | N
-
-### ListItem Events
-
-名称 | 参数 | 描述
--- | -- | --
-click | `(context: { e: MouseEvent })` | 点击时触发
### ListItemMeta Props
-名称 | 类型 | 默认值 | 说明 | 必传
+名称 | 类型 | 默认值 | 描述 | 必传
-- | -- | -- | -- | --
avatar | String / Slot / Function | - | 已废弃。列表项图片。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N
description | String / Slot / Function | - | 列表项内容。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-vue/blob/develop/src/common.ts) | N
diff --git a/src/list/list.tsx b/src/list/list.tsx
index 1ec2af613..d54ab27ff 100644
--- a/src/list/list.tsx
+++ b/src/list/list.tsx
@@ -1,102 +1,130 @@
-import { VNode } from 'vue';
-import { ScopedSlotReturnValue } from 'vue/types/vnode';
-import Loading from '../loading';
+import { defineComponent, computed, ref } from '@vue/composition-api';
+import isString from 'lodash/isString';
+import omit from 'lodash/omit';
+import TLoading from '../loading';
+import TListItem from './list-item';
import props from './props';
-import { renderTNodeJSX } from '../utils/render-tnode';
import { LOAD_MORE, LOADING } from './const';
-import { ClassName } from '../common';
-import { getClassPrefixMixins } from '../config-provider/config-receiver';
-import mixins from '../utils/mixins';
-
-const classPrefixMixins = getClassPrefixMixins('list');
+import { useConfig, usePrefixClass, useCommonClassName } from '../hooks/useConfig';
+import useListVirtualScroll from './hooks/useListVirtualScroll';
+import { renderTNodeJSX } from '../utils/render-tnode';
+import useListItems from './hooks/useListItem';
+import type { TdListProps } from './type';
-export default mixins(classPrefixMixins).extend({
+export default defineComponent({
name: 'TList',
- props: {
- ...props,
- },
- computed: {
- listClass(): ClassName {
- return [
- `${this.componentName}`,
- this.commonSizeClassName[this.size],
- {
- [`${this.componentName}--split`]: this.split,
- [`${this.componentName}--stripe`]: this.stripe,
- [`${this.componentName}--vertical-action`]: this.layout === 'vertical',
- },
- ];
- },
- loadingClass(): ClassName {
- if (this.asyncLoading === 'loading') return this.commonStatusClassName.loading;
- if (this.asyncLoading === 'load-more') return this.commonStatusClassName.loadMore;
- return '';
- },
- },
- components: {
- Loading,
- },
- methods: {
- renderLoading() {
- if (this.asyncLoading && typeof this.asyncLoading === 'string') {
- const text = {
- [LOADING]: '正在加载中,请稍后',
- [LOAD_MORE]: '点击加载更多',
- }[this.asyncLoading];
- const loading = this.asyncLoading === LOADING;
- return
;
- }
- return renderTNodeJSX(this, 'asyncLoading');
- },
- handleScroll(e: WheelEvent | Event) {
- const listElement = this.$el as HTMLElement;
+ props,
+ setup(props: TdListProps, { emit }) {
+ const listRef = ref();
+
+ const { globalConfig } = useConfig('list');
+ const componentName = usePrefixClass('list');
+ const { SIZE } = useCommonClassName();
+ const { listItems } = useListItems();
+ const listClass = computed(() => [
+ `${componentName.value}`,
+ SIZE.value[props.size],
+ {
+ [`${componentName.value}--split`]: props.split,
+ [`${componentName.value}--stripe`]: props.stripe,
+ [`${componentName.value}--vertical-action`]: props.layout === 'vertical',
+ },
+ ]);
+
+ const loadingClass = computed(() => isString(props.asyncLoading) && ['loading', 'load-more'].includes(props.asyncLoading)
+ ? `${componentName.value}__load ${componentName.value}__load--${props.asyncLoading}`
+ : `${componentName.value}__load`);
+
+ const {
+ virtualConfig, cursorStyle, listStyle, isVirtualScroll, onInnerVirtualScroll,
+ } = useListVirtualScroll(
+ props.scroll,
+ listRef,
+ listItems,
+ );
+ const handleScroll = (e: WheelEvent) => {
+ const listElement = e.target as HTMLElement;
const { scrollTop, scrollHeight, clientHeight } = listElement;
- this.$emit('scroll', {
- $event: e,
+ if (isVirtualScroll.value) onInnerVirtualScroll(e);
+ const scrollParams = {
+ e,
scrollTop,
scrollBottom: scrollHeight - clientHeight - scrollTop,
- });
- if (this.onScroll) {
- this.onScroll({
- e,
- scrollTop,
- scrollBottom: scrollHeight - clientHeight - scrollTop,
- });
- }
- },
- handleLoadMore(e: MouseEvent) {
- if (typeof this.asyncLoading === 'string' && this.asyncLoading !== LOAD_MORE) return;
- this.$emit('load-more', { e });
- if (this.onLoadMore) {
- this.onLoadMore({
- e,
- });
- }
- },
- renderContent() {
- const propsHeaderContent = renderTNodeJSX(this, 'header');
- const propsFooterContent = renderTNodeJSX(this, 'footer');
+ };
+ emit('scroll', scrollParams);
+
+ props.onScroll?.(scrollParams);
+ };
- return [
- propsHeaderContent && ,
-
{renderTNodeJSX(this, 'default')}
,
- propsFooterContent && ,
- ];
- },
+ const handleLoadMore = (e: MouseEvent) => {
+ if (isString(props.asyncLoading) && props.asyncLoading !== LOAD_MORE) return;
+ emit('load-more', { e });
+ props.onLoadMore?.({ e });
+ };
+
+ return {
+ componentName,
+ listClass,
+ loadingClass,
+ handleScroll,
+ handleLoadMore,
+ listRef,
+ globalConfig,
+ virtualConfig,
+ cursorStyle,
+ listStyle,
+ isVirtualScroll,
+ };
},
- render(): VNode {
- let listContent: ScopedSlotReturnValue = this.renderContent();
- listContent = [
- listContent,
-
- {this.renderLoading()}
-
,
- ];
+ render() {
+ const {
+ isVirtualScroll, cursorStyle, listStyle, componentName, globalConfig, virtualConfig,
+ } = this;
+
+ const propsHeaderContent = renderTNodeJSX(this, 'header');
+ const propsFooterContent = renderTNodeJSX(this, 'footer');
+ const renderLoading = () => {
+ if (this.asyncLoading && isString(this.asyncLoading)) {
+ if (this.asyncLoading === LOADING) {
+ return (
+
+
+ {globalConfig.loadingText}
+
+ );
+ }
+ if (this.asyncLoading === LOAD_MORE) {
+ return
{globalConfig.loadingMoreText};
+ }
+ }
+ return renderTNodeJSX(this, 'asyncLoading');
+ };
return (
-
- {listContent}
+
+ {propsHeaderContent ? : null}
+ {isVirtualScroll ? (
+
+
+
+ {virtualConfig.visibleData.value.map((item) => (
+
+ ))}
+
+
+ ) : (
+
{renderTNodeJSX(this, 'default')}
+ )}
+ {propsFooterContent ? : null}
+
+ {renderLoading()}
+
);
},
diff --git a/src/list/props.ts b/src/list/props.ts
index e931c5d15..51e570ce9 100644
--- a/src/list/props.ts
+++ b/src/list/props.ts
@@ -2,7 +2,6 @@
/**
* 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC
- * updated at 2021-11-19 10:44:26
* */
import { TdListProps } from './type';
@@ -26,14 +25,20 @@ export default {
type: String as PropType
,
default: 'horizontal' as TdListProps['layout'],
validator(val: TdListProps['layout']): boolean {
+ if (!val) return true;
return ['horizontal', 'vertical'].includes(val);
},
},
+ /** 懒加载和虚拟滚动。为保证组件收益最大化,当数据量小于阈值 `scroll.threshold` 时,无论虚拟滚动的配置是否存在,组件内部都不会开启虚拟滚动,`scroll.threshold` 默认为 `100` */
+ scroll: {
+ type: Object as PropType,
+ },
/** 尺寸 */
size: {
type: String as PropType,
default: 'medium' as TdListProps['size'],
validator(val: TdListProps['size']): boolean {
+ if (!val) return true;
return ['small', 'medium', 'large'].includes(val);
},
},
diff --git a/src/list/type.ts b/src/list/type.ts
index 35d685e84..74b4e47b2 100644
--- a/src/list/type.ts
+++ b/src/list/type.ts
@@ -2,10 +2,9 @@
/**
* 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC
- * updated at 2021-11-19 10:44:26
* */
-import { TNode } from '../common';
+import { TNode, TScroll } from '../common';
export interface TdListProps {
/**
@@ -25,6 +24,10 @@ export interface TdListProps {
* @default horizontal
*/
layout?: 'horizontal' | 'vertical';
+ /**
+ * 懒加载和虚拟滚动。为保证组件收益最大化,当数据量小于阈值 `scroll.threshold` 时,无论虚拟滚动的配置是否存在,组件内部都不会开启虚拟滚动,`scroll.threshold` 默认为 `100`
+ */
+ scroll?: TScroll;
/**
* 尺寸
* @default medium
@@ -65,6 +68,7 @@ export interface TdListItemProps {
default?: string | TNode;
/**
* 点击时触发
+ * @deprecated
*/
onClick?: (context: { e: MouseEvent }) => void;
}
diff --git a/test/snap/__snapshots__/csr.test.js.snap b/test/snap/__snapshots__/csr.test.js.snap
index a1f953588..c1b1cfbb8 100644
--- a/test/snap/__snapshots__/csr.test.js.snap
+++ b/test/snap/__snapshots__/csr.test.js.snap
@@ -68023,9 +68023,11 @@ exports[`csr snapshot test > csr test ./src/list/_example/loading.vue 1`] = `
-
+
+ 点击加载更多
+
@@ -68927,6 +68929,1137 @@ exports[`csr snapshot test > csr test ./src/list/_example/stripe.vue 1`] = `
`;
+exports[`csr snapshot test > csr test ./src/list/_example/virtual-scroll.vue 1`] = `
+