tanjinzhou
4 years ago
14 changed files with 25 additions and 485 deletions
@ -1,214 +0,0 @@
|
||||
/* eslint-disable arrow-body-style */ |
||||
|
||||
import * as React from 'react'; |
||||
// @ts-ignore
|
||||
import CSSMotion from 'rc-animate/lib/CSSMotion'; |
||||
import classNames from 'classnames'; |
||||
import List, { ListRef } from '../src/List'; |
||||
import './animate.less'; |
||||
|
||||
let uuid = 0; |
||||
function genItem() { |
||||
const item = { |
||||
id: `key_${uuid}`, |
||||
uuid, |
||||
}; |
||||
uuid += 1; |
||||
return item; |
||||
} |
||||
|
||||
const originData: Item[] = []; |
||||
for (let i = 0; i < 1000; i += 1) { |
||||
originData.push(genItem()); |
||||
} |
||||
|
||||
interface Item { |
||||
id: string; |
||||
uuid: number; |
||||
} |
||||
|
||||
interface MyItemProps extends Item { |
||||
visible: boolean; |
||||
motionAppear: boolean; |
||||
onClose: (id: string) => void; |
||||
onLeave: (id: string) => void; |
||||
onAppear: (...args: any[]) => void; |
||||
onInsertBefore: (id: string) => void; |
||||
onInsertAfter: (id: string) => void; |
||||
} |
||||
|
||||
const getCurrentHeight = (node: HTMLElement) => ({ height: node.offsetHeight }); |
||||
const getMaxHeight = (node: HTMLElement) => { |
||||
return { height: node.scrollHeight }; |
||||
}; |
||||
const getCollapsedHeight = () => ({ height: 0, opacity: 0 }); |
||||
|
||||
const MyItem: React.ForwardRefRenderFunction<any, MyItemProps> = ( |
||||
{ |
||||
id, |
||||
uuid: itemUuid, |
||||
visible, |
||||
onClose, |
||||
onLeave, |
||||
onAppear, |
||||
onInsertBefore, |
||||
onInsertAfter, |
||||
motionAppear, |
||||
}, |
||||
ref, |
||||
) => { |
||||
const motionRef = React.useRef(false); |
||||
React.useEffect(() => { |
||||
return () => { |
||||
if (motionRef.current) { |
||||
onAppear(); |
||||
} |
||||
}; |
||||
}, []); |
||||
|
||||
return ( |
||||
<CSSMotion |
||||
visible={visible} |
||||
ref={ref} |
||||
motionName="motion" |
||||
motionAppear={motionAppear} |
||||
onAppearStart={getCollapsedHeight} |
||||
onAppearActive={node => { |
||||
motionRef.current = true; |
||||
return getMaxHeight(node); |
||||
}} |
||||
onAppearEnd={onAppear} |
||||
onLeaveStart={getCurrentHeight} |
||||
onLeaveActive={getCollapsedHeight} |
||||
onLeaveEnd={() => { |
||||
onLeave(id); |
||||
}} |
||||
> |
||||
{({ className, style }, passedMotionRef) => { |
||||
return ( |
||||
<div |
||||
ref={passedMotionRef} |
||||
className={classNames('item', className)} |
||||
style={style} |
||||
data-id={id} |
||||
> |
||||
<div style={{ height: itemUuid % 2 ? 100 : undefined }}> |
||||
<button |
||||
type="button" |
||||
onClick={() => { |
||||
onClose(id); |
||||
}} |
||||
> |
||||
Close |
||||
</button> |
||||
<button |
||||
type="button" |
||||
onClick={() => { |
||||
onInsertBefore(id); |
||||
}} |
||||
> |
||||
Insert Before |
||||
</button> |
||||
<button |
||||
type="button" |
||||
onClick={() => { |
||||
onInsertAfter(id); |
||||
}} |
||||
> |
||||
Insert After |
||||
</button> |
||||
{id} |
||||
</div> |
||||
</div> |
||||
); |
||||
}} |
||||
</CSSMotion> |
||||
); |
||||
}; |
||||
|
||||
const ForwardMyItem = React.forwardRef(MyItem); |
||||
|
||||
const Demo = () => { |
||||
const [data, setData] = React.useState(originData); |
||||
const [closeMap, setCloseMap] = React.useState<{ [id: number]: boolean }>({}); |
||||
const [animating, setAnimating] = React.useState(false); |
||||
const [insertIndex, setInsertIndex] = React.useState<number>(); |
||||
|
||||
const listRef = React.useRef<ListRef>(); |
||||
|
||||
const onClose = (id: string) => { |
||||
setCloseMap({ |
||||
...closeMap, |
||||
[id]: true, |
||||
}); |
||||
}; |
||||
|
||||
const onLeave = (id: string) => { |
||||
const newData = data.filter(item => item.id !== id); |
||||
setData(newData); |
||||
}; |
||||
|
||||
const onAppear = (...args: any[]) => { |
||||
console.log('Appear:', args); |
||||
setAnimating(false); |
||||
}; |
||||
|
||||
function lockForAnimation() { |
||||
setAnimating(true); |
||||
} |
||||
|
||||
const onInsertBefore = (id: string) => { |
||||
const index = data.findIndex(item => item.id === id); |
||||
const newData = [...data.slice(0, index), genItem(), ...data.slice(index)]; |
||||
setInsertIndex(index); |
||||
setData(newData); |
||||
lockForAnimation(); |
||||
}; |
||||
const onInsertAfter = (id: string) => { |
||||
const index = data.findIndex(item => item.id === id) + 1; |
||||
const newData = [...data.slice(0, index), genItem(), ...data.slice(index)]; |
||||
setInsertIndex(index); |
||||
setData(newData); |
||||
lockForAnimation(); |
||||
}; |
||||
|
||||
return ( |
||||
<React.StrictMode> |
||||
<div> |
||||
<h2>Animate</h2> |
||||
<p>Current: {data.length} records</p> |
||||
|
||||
<List<Item> |
||||
data={data} |
||||
data-id="list" |
||||
height={200} |
||||
itemHeight={20} |
||||
itemKey="id" |
||||
// disabled={animating}
|
||||
ref={listRef} |
||||
style={{ |
||||
border: '1px solid red', |
||||
boxSizing: 'border-box', |
||||
}} |
||||
// onSkipRender={onAppear}
|
||||
// onItemRemove={onAppear}
|
||||
> |
||||
{(item, index) => ( |
||||
<ForwardMyItem |
||||
{...item} |
||||
motionAppear={animating && insertIndex === index} |
||||
visible={!closeMap[item.id]} |
||||
onClose={onClose} |
||||
onLeave={onLeave} |
||||
onAppear={onAppear} |
||||
onInsertBefore={onInsertBefore} |
||||
onInsertAfter={onInsertAfter} |
||||
/> |
||||
)} |
||||
</List> |
||||
</div> |
||||
</React.StrictMode> |
||||
); |
||||
}; |
||||
|
||||
export default Demo; |
@ -1,60 +0,0 @@
|
||||
import * as React from 'react'; |
||||
import List from '../src/List'; |
||||
|
||||
interface Item { |
||||
id: number; |
||||
height: number; |
||||
} |
||||
|
||||
const MyItem: React.FC<Item> = ({ id, height }, ref) => { |
||||
return ( |
||||
<span |
||||
ref={ref} |
||||
style={{ |
||||
border: '1px solid gray', |
||||
padding: '0 16px', |
||||
height, |
||||
lineHeight: '30px', |
||||
boxSizing: 'border-box', |
||||
display: 'inline-block', |
||||
}} |
||||
> |
||||
{id} |
||||
</span> |
||||
); |
||||
}; |
||||
|
||||
const ForwardMyItem = React.forwardRef(MyItem); |
||||
|
||||
const data: Item[] = []; |
||||
for (let i = 0; i < 100; i += 1) { |
||||
data.push({ |
||||
id: i, |
||||
height: 30 + (i % 2 ? 70 : 0), |
||||
}); |
||||
} |
||||
|
||||
const Demo = () => { |
||||
return ( |
||||
<React.StrictMode> |
||||
<div> |
||||
<h2>Dynamic Height</h2> |
||||
|
||||
<List |
||||
data={data} |
||||
height={500} |
||||
itemHeight={30} |
||||
itemKey="id" |
||||
style={{ |
||||
border: '1px solid red', |
||||
boxSizing: 'border-box', |
||||
}} |
||||
> |
||||
{item => <ForwardMyItem {...item} />} |
||||
</List> |
||||
</div> |
||||
</React.StrictMode> |
||||
); |
||||
}; |
||||
|
||||
export default Demo; |
@ -1,86 +0,0 @@
|
||||
import * as React from 'react'; |
||||
import List from '../src/List'; |
||||
|
||||
interface Item { |
||||
id: number; |
||||
height: number; |
||||
} |
||||
|
||||
const MyItem: React.FC<Item> = ({ id, height }, ref) => { |
||||
return ( |
||||
<span |
||||
ref={ref} |
||||
style={{ |
||||
border: '1px solid gray', |
||||
padding: '0 16px', |
||||
height, |
||||
lineHeight: '30px', |
||||
boxSizing: 'border-box', |
||||
display: 'inline-block', |
||||
}} |
||||
> |
||||
{id} |
||||
</span> |
||||
); |
||||
}; |
||||
|
||||
const ForwardMyItem = React.forwardRef(MyItem); |
||||
|
||||
const data: Item[] = []; |
||||
for (let i = 0; i < 100; i += 1) { |
||||
data.push({ |
||||
id: i, |
||||
height: 30 + (i % 2 ? 20 : 0), |
||||
}); |
||||
} |
||||
|
||||
const Demo = () => { |
||||
return ( |
||||
<React.StrictMode> |
||||
<div> |
||||
<h2>Less Count</h2> |
||||
<List |
||||
data={data.slice(0, 1)} |
||||
itemHeight={30} |
||||
height={100} |
||||
itemKey="id" |
||||
style={{ |
||||
border: '1px solid red', |
||||
boxSizing: 'border-box', |
||||
}} |
||||
> |
||||
{item => <ForwardMyItem {...item} />} |
||||
</List> |
||||
|
||||
<h2>Less Item Height</h2> |
||||
<List |
||||
data={data.slice(0, 10)} |
||||
itemHeight={1} |
||||
height={100} |
||||
itemKey="id" |
||||
style={{ |
||||
border: '1px solid red', |
||||
boxSizing: 'border-box', |
||||
}} |
||||
> |
||||
{item => <ForwardMyItem {...item} />} |
||||
</List> |
||||
|
||||
<h2>Without Height</h2> |
||||
<List |
||||
data={data} |
||||
itemHeight={30} |
||||
itemKey="id" |
||||
style={{ |
||||
border: '1px solid red', |
||||
boxSizing: 'border-box', |
||||
}} |
||||
> |
||||
{item => <ForwardMyItem {...item} />} |
||||
</List> |
||||
</div> |
||||
</React.StrictMode> |
||||
); |
||||
}; |
||||
|
||||
export default Demo; |
@ -1,106 +0,0 @@
|
||||
/* eslint-disable jsx-a11y/label-has-associated-control, jsx-a11y/label-has-for */ |
||||
import * as React from 'react'; |
||||
import List from '../src/List'; |
||||
|
||||
interface Item { |
||||
id: number; |
||||
} |
||||
|
||||
const MyItem: React.FC<Item> = ({ id }, ref) => ( |
||||
<span |
||||
ref={ref} |
||||
style={{ |
||||
border: '1px solid gray', |
||||
padding: '0 16px', |
||||
height: 30, |
||||
lineHeight: '30px', |
||||
boxSizing: 'border-box', |
||||
display: 'inline-block', |
||||
}} |
||||
> |
||||
{id} |
||||
</span> |
||||
); |
||||
|
||||
const ForwardMyItem = React.forwardRef(MyItem); |
||||
|
||||
function getData(count: number) { |
||||
const data: Item[] = []; |
||||
for (let i = 0; i < count; i += 1) { |
||||
data.push({ |
||||
id: i, |
||||
}); |
||||
} |
||||
return data; |
||||
} |
||||
|
||||
const Demo = () => { |
||||
const [height, setHeight] = React.useState(100); |
||||
const [data, setData] = React.useState(getData(20)); |
||||
|
||||
return ( |
||||
<React.StrictMode> |
||||
<div style={{ height: '150vh' }}> |
||||
<h2>Switch</h2> |
||||
<span |
||||
onChange={(e: any) => { |
||||
setData(getData(Number(e.target.value))); |
||||
}} |
||||
> |
||||
Data |
||||
<label> |
||||
<input type="radio" name="switch" value={0} />0 |
||||
</label> |
||||
<label> |
||||
<input type="radio" name="switch" value={2} />2 |
||||
</label> |
||||
<label> |
||||
<input type="radio" name="switch" value={100} /> |
||||
100 |
||||
</label> |
||||
<label> |
||||
<input type="radio" name="switch" value={200} /> |
||||
200 |
||||
</label> |
||||
<label> |
||||
<input type="radio" name="switch" value={1000} /> |
||||
1000 |
||||
</label> |
||||
</span> |
||||
<span |
||||
onChange={(e: any) => { |
||||
setHeight(Number(e.target.value)); |
||||
}} |
||||
> |
||||
| Height |
||||
<label> |
||||
<input type="radio" name="switch" value={0} />0 |
||||
</label> |
||||
<label> |
||||
<input type="radio" name="switch" value={100} /> |
||||
100 |
||||
</label> |
||||
<label> |
||||
<input type="radio" name="switch" value={200} /> |
||||
200 |
||||
</label> |
||||
</span> |
||||
|
||||
<List |
||||
data={data} |
||||
height={height} |
||||
itemHeight={30} |
||||
itemKey="id" |
||||
style={{ |
||||
border: '1px solid red', |
||||
boxSizing: 'border-box', |
||||
}} |
||||
> |
||||
{(item, _, props) => <ForwardMyItem {...item} {...props} />} |
||||
</List> |
||||
</div> |
||||
</React.StrictMode> |
||||
); |
||||
}; |
||||
|
||||
export default Demo; |
Loading…
Reference in new issue