Skip to content

Commit

Permalink
feat(list): add list component
Browse files Browse the repository at this point in the history
  • Loading branch information
realcwang committed Aug 16, 2024
1 parent 1438ed7 commit 565d530
Show file tree
Hide file tree
Showing 16 changed files with 456 additions and 6 deletions.
2 changes: 2 additions & 0 deletions site/mobile/components/style/index.less
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@

#app {
min-height: 100vh;
height: 100vh;
display: flex;
flex-direction: column;
}

.tdesign-mobile-demo {
flex: 1;
overflow-y: scroll;
}
5 changes: 5 additions & 0 deletions site/mobile/mobile.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ export default {
name: 'grid',
component: () => import('tdesign-mobile-react/grid/_example/base.jsx'),
},
{
title: 'List 列表',
name: 'list',
component: () => import('tdesign-mobile-react/list/_example/index.jsx'),
},
{
title: 'Image 图片',
name: 'image',
Expand Down
12 changes: 6 additions & 6 deletions site/web/site.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -239,12 +239,12 @@ export default {
path: '/mobile-react/components/image',
component: () => import('tdesign-mobile-react/image/image.md'),
},
// {
// title: 'List 列表',
// name: 'list',
// path: '/mobile-react/components/list',
// component: () => import('tdesign-mobile-react/list/list.md'),
// },
{
title: 'List 列表',
name: 'list',
path: '/mobile-react/components/list',
component: () => import('tdesign-mobile-react/list/list.md'),
},
// {
// title: 'ImageViewer 图片预览',
// name: 'image-viewer',
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export * from './sticky';
export * from './swiper';
export * from './swipe-cell';
export * from './tag';
export * from './list';

/**
* 消息提醒(7个)
Expand Down
59 changes: 59 additions & 0 deletions src/list/_example/base.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React, { useEffect, useState, useRef} from 'react';
import './style/index.less';
import { Cell, List } from 'tdesign-mobile-react';

export default function ListDemo() {
const [isLoading, setIsLoading] = useState(false);
const pageSize = 20;
const stateRef = useRef([]);
const pageRef = useRef(1);
const dataSource = [];
const total = 100;
for (let i = 0; i < total; i++) {
dataSource.push({
id: i,
content: '列表内容列表内容列表内容',
icon: 'https://tdesign.gtimg.com/list-icon.png',
title: '列表主内容',
});
}

// 模拟请求
const fetchData = async (pageInfo) => {
if (isLoading) return;
setIsLoading(true);
try {
setTimeout(() => {
const { pageNum, pageSize } = pageInfo;
const newDataSource = dataSource.slice((pageNum - 1) * pageSize, pageNum * pageSize);
const newListData = stateRef.current.concat(newDataSource);
pageRef.current = pageNum
stateRef.current = newListData
setIsLoading(false);
}, 0);
} catch (err) {
stateRef.current = []
}
};

const onScroll = (scrollBottom) => {
if (!scrollBottom && stateRef.current.length < total) {
fetchData({ pageNum: pageRef.current + 1, pageSize });
}
}

useEffect(() => {
fetchData({ pageNum: pageRef.current, pageSize });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

return (
<List asyncLoading={isLoading} onScroll={onScroll}>
{
stateRef.current.map((item) => <Cell key={item.id} align="middle">
<span className="cell">{item.id}</span>
</Cell>)
}
</List>
);
}
56 changes: 56 additions & 0 deletions src/list/_example/err-tip.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React, { useState, useRef, useEffect } from 'react';
import { Cell, List, Loading } from 'tdesign-mobile-react';

export default function ListDemo() {
const listError = useRef([])
const [loading, setLoading] = useState('')
const [showError, setShowError] = useState(false)

const onLoadError = () => {
setLoading('loading')

setTimeout(() => {
const newVal = [...listError.current]
for (let i = listError.current.length; i < 8; i++) {
newVal.push(`${i}`);
}
listError.current = newVal;

setShowError(true)
setLoading('')
}, 1000);
};

const onLoadMore = () => {
setShowError(false)
if (listError.current.length >= 60 || loading) {
return;
}
setLoading('loading')

setTimeout(() => {
for (let i = 0; i < 15; i++) {
listError.current.push(`${listError.current.length + 1}`)
}
setLoading('')
}, 1000);
};

useEffect(()=>{
onLoadError()
}, []);

return (
<List asyncLoading={loading} onScroll={onLoadMore} footer={
showError && <Loading indicator={false}>
<div className="custom-error">请求失败,点击重新<span onClick={onLoadMore}>加载</span></div>
</Loading>
}>
{
listError.current.map((item) => <Cell key={item} align="middle">
<span className="cell">{item}</span>
</Cell>)
}
</List>
);
}
53 changes: 53 additions & 0 deletions src/list/_example/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React, { useState } from 'react';
import { Button } from 'tdesign-mobile-react';
import TDemoBlock from '../../../site/mobile/components/DemoBlock';
// import TDemoHeader from '../../../site/mobile/components/DemoHeader';
import './style/index.less'

import BaseList from './base.jsx';
import ErrTipDemo from './err-tip.jsx';
import PullRefreshDemo from './pull-refresh.jsx';


export default function ListDemo() {

const [currentTab, setCurrentTab] = useState('info')

const onChangeTab = (val) => {
setCurrentTab(val);
history.pushState({}, '', '?tab=demo');
};

return (
<div className="tdesign-mobile-demo">
<div className="list-demo">
{ currentTab === 'info' && <div>
<h1 className="title">List 列表</h1>
<p className="summary">
瀑布流滚动加载,用于展示同一类型信息的长列表。当列表即将滚动到底部时,会触发事件并加载更多列表项。
</p>
<TDemoBlock title="01 类型" summary="基础列表">
<Button size="large" variant="outline" theme="primary" onClick={()=>onChangeTab('base')}> 基础列表 </Button>
<Button size="large" variant="outline" theme="primary" onClick={()=>onChangeTab('pull-refresh')}>
下拉刷新
</Button>
<Button size="large" variant="outline" theme="primary" onClick={()=>onChangeTab('error-tip')}>
错误提示
</Button>
</TDemoBlock>
</div>}
{
currentTab === 'base' && <BaseList></BaseList>
}
{
currentTab === 'error-tip' && <ErrTipDemo></ErrTipDemo>
}
{
currentTab === 'pull-refresh' && <div className="pull-refresh-wrap">
<PullRefreshDemo />
</div>
}
</div>
</div>
);
}
70 changes: 70 additions & 0 deletions src/list/_example/pull-refresh.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import React, { useState, useEffect, useRef } from 'react';
import { Cell, List, PullDownRefresh } from 'tdesign-mobile-react';

export default function ListDemo() {
const [loading, setLoading] = useState('')
const [refreshing, setRefreshing] = useState(false)

const listData = useRef([])

const MAX_DATA_LEN = 60;

const loadData = (isRefresh) => {
const ONCE_LOAD_NUM = 20;
return new Promise((resolve) => {
setTimeout(() => {
const temp = [];
for (let i = 0; i < ONCE_LOAD_NUM; i++) {
if (isRefresh) {
temp.push(`${i + 1}`);
} else {
temp.push(`${listData.current.length + 1 + i}`);
}
}

if (isRefresh) {
listData.current = temp
} else {
listData.current= [...listData.current, ...temp ]
}
setLoading('');
setRefreshing(false);
}, 1000);
});
};

const onLoadData = (isRefresh) => {
if ((listData.current.length >= MAX_DATA_LEN && !isRefresh) || loading.value) {
return;
}
setLoading('loading');
loadData(isRefresh)
};

const onScroll = (scrollBottom) => {
if (scrollBottom < 50) {
onLoadData();
}
};

const onRefresh = () => {
setRefreshing(true);
onLoadData(true);
};

useEffect(()=>{
onLoadData();
}, []);

return (
<PullDownRefresh value={refreshing} onChange={(val)=>setRefreshing(val)} onRefresh={onRefresh}>
<List asyncLoading={loading} onScroll={onScroll}>
{
listData.current.map((item) => <Cell key={item} align="middle">
<span className="cell">{item}</span>
</Cell>)
}
</List>
</PullDownRefresh>
);
}
30 changes: 30 additions & 0 deletions src/list/_example/style/index.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
.list-demo {
.t-list {
.cell {
width: 100%;
text-align: center;
}
.error {
text-align: center;
color: #969799;
font-size: 14px;
margin-top: 8px;
}
}
.custom-error {
font-size: 14px;
color: #969799;
text-align: center;
padding-top: 16px;
cursor: default;

span {
color: #0052d9;
cursor: pointer;
}
}
.t-button {
margin: 0 16px 16px 16px;
width: calc(100% - 32px);
}
}
8 changes: 8 additions & 0 deletions src/list/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import _List from './list';

import './style/index.js';

export * from './type';

export const List = _List;
export default List;
13 changes: 13 additions & 0 deletions src/list/list.en-US.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
:: BASE_DOC ::

## API

### List Props

name | type | default | description | required
-- | -- | -- | -- | --
asyncLoading | TNode / Function | - | Typescript:`string \| TNode`[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
footer | TNode / Function | - | Typescript:`string \| TNode`[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
header | TNode / Function | - | Typescript:`string \| TNode`[see more ts definition](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
onLoadMore | Function | | Typescript:`() => void`<br/> | N
onScroll | Function | | Typescript:`(bottomDistance: number, scrollTop: number) => void`<br/> | N
13 changes: 13 additions & 0 deletions src/list/list.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
:: BASE_DOC ::

## API

### List Props

名称 | 类型 | 默认值 | 描述 | 必传
-- | -- | -- | -- | --
asyncLoading | String / TNode | - | 自定义加载中。值为空不显示加载中,值为 'loading' 显示加载中状态,值为 'load-more' 显示加载更多状态。值类型为函数,则表示自定义加载状态呈现内容。TS 类型:`string \| TNode`[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
footer | String / TNode | - | 底部。TS 类型:`string \| TNode`[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
header | String / TNode | - | 头部。TS 类型:`string \| TNode`[通用类型定义](https://github.com/Tencent/tdesign-mobile-vue/blob/develop/src/common.ts) | N
onLoadMore | Function | | TS 类型:`() => void`<br/>点击加载更多时触发 | N
onScroll | Function | | TS 类型:`(bottomDistance: number, scrollTop: number) => void`<br/>列表滚动时触发,bottomDistance 表示底部距离;scrollTop 表示顶部滚动距离 | N
Loading

0 comments on commit 565d530

Please sign in to comment.