Skip to content

Commit

Permalink
Merge pull request alibaba-fusion#58 from alibaba-fusion/feat/virtual…
Browse files Browse the repository at this point in the history
…-list

Feat/virtual list
  • Loading branch information
youluna authored Nov 27, 2018
2 parents 84b2288 + 8d860e8 commit 53964f7
Show file tree
Hide file tree
Showing 12 changed files with 262 additions and 71 deletions.
52 changes: 52 additions & 0 deletions docs/select/demo/virtual-select.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# 无限滚动

- order: 15

select 配合无限滚动

:::lang=en-us
# virtual-select

- order: 15

select with virtual list
:::
---

````jsx
import { Select } from '@alifd/next';

const Option = Select.Option;

const onChange = function (value) {
console.log(value);
};

function generateItem(index) {
return {label: `option${index}`, value: `option${index}`};
}

function generateOption(index) {
return <Option key={`option${index}`} value={`option${index}`}>{`option${index}`}</Option>;
}

function generateData(len, isOption) {
const data = [];

for (let i = 0; i < len; i++) {
isOption ? data.push(generateOption(i)) : data.push(generateItem(i));
}

return data;
}

ReactDOM.render(
<div>
<Select dataSource={generateData(100)} useVirtual onChange={onChange} defaultValue="option0" />
&nbsp;&nbsp;&nbsp;&nbsp;
<Select useVirtual onChange={onChange} defaultValue="option50">
{generateData(100, true)}
</Select>
</div>
, mountNode);
````
2 changes: 0 additions & 2 deletions docs/virtual-list/demo/basic.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ const generateLi = (index = 'index') => {
for (let i = 0; i < 1000; i++) {
dataSource.push(generateLi(i));
}
console.log(dataSource)
const getHeight = index => index % 3 === 0 ? 20 : 30;

const demo = (
<div className={'virtual-box'}>
Expand Down
25 changes: 5 additions & 20 deletions docs/virtual-list/demo/initial-index.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# 设置初始位置

- order: 0
- order: 1

使用 jumpIndex 设置初始位置

:::lang=en-us
# Basic

- order: 0
- order: 1

Use jumpIndex to set first item.

Expand All @@ -21,11 +21,7 @@ import { VirtualList } from '@alifd/next';
const dataSource = [];

function generateLi(index) {
if (index % 3 === 0) {
return (<li key={`key-${index}`} style={{lineHeight: '30px', background: '#5f83ff', color: '#fff'}}>key-{index}</li>);
} else {
return (<li key={`key-${index}`} style={{lineHeight: '20px'}}>key-{index}</li>);
}
return (<li key={`key-${index}`} style={{lineHeight: '20px'}}>key-{index}</li>);
}
function generateData(len) {
for (let i = 0; i < len; i++) {
Expand All @@ -35,20 +31,9 @@ function generateData(len) {

class App extends React.Component {
state = {
initial: 20,
initial: 50,
dataSource: generateData(1000)
}
componentDidMount() {
setTimeout(()=> {
const instance = this.refs.virtual.getInstance();
instance.scrollTo(50);
}, 200);

}

getHeight(index) {
return index % 3 === 0 ? 30 : 20;
}
onClick() {
this.setState({
initial: this.state.initial + 20
Expand All @@ -61,7 +46,7 @@ class App extends React.Component {
<br/>
<br/>
<div className={'virtual-box'}>
<VirtualList ref="virtual" jumpIndex={this.state.initial} itemSizeGetter={this.getHeight.bind(this)}>
<VirtualList ref="virtual" jumpIndex={this.state.initial}>
{dataSource}
</VirtualList>
</div>
Expand Down
95 changes: 95 additions & 0 deletions docs/virtual-list/demo/item-size-getter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# 不等高的item

- order: 2

使用 jumpIndex 设置初始位置, 并设置 itemSizeGetter

:::lang=en-us
# Basic

- order: 2

Use jumpIndex and itemSizeGetter to set first item in visual area.

:::

---

````jsx
import { VirtualList } from '@alifd/next';

const dataSource = [];

function generateLi(index) {
if (index % 3 === 0) {
return (<li key={`key-${index}`} style={{lineHeight: '30px', background: '#5f83ff', color: '#fff'}}>key-{index}</li>);
} else {
return (<li key={`key-${index}`} style={{lineHeight: '20px'}}>key-{index}</li>);
}
}
function generateData(len) {
for (let i = 0; i < len; i++) {
dataSource.push(generateLi(i));
}
}

class App extends React.Component {
state = {
initial: 20,
dataSource: generateData(1000)
}

componentDidMount() {
setTimeout(()=> {
const instance = this.refs.virtual.getInstance();
instance.scrollTo(50);
}, 200);

}

getHeight(index) {
return index % 3 === 0 ? 30 : 20;
}

onClick() {
this.setState({
initial: this.state.initial + 20
})
}

render() {
return (
<div>
<button onClick={this.onClick.bind(this)}>jump to {this.state.initial + 20}</button>
<br/>
<br/>
<div className={'virtual-box'}>
<VirtualList ref="virtual" jumpIndex={this.state.initial} itemSizeGetter={this.getHeight.bind(this)}>
{dataSource}
</VirtualList>
</div>
</div>
);
}
}

ReactDOM.render(<App />, mountNode);
````

````css
.virtual-box {
height: 200px;
width: 200px;
border: 1px solid #ddd;
overflow: auto;
}
.virtual-box ul {
padding: 0;
margin: 0;
list-style: none;
}
.virtual-box li {
padding-left: 10px;
border-bottom: 1px solid #333;
}
````
2 changes: 1 addition & 1 deletion docs/virtual-list/index.en-us.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@
| itemsRenderer | items parent dom,by default (items, ref) => <ul ref={ref}>{items}</ul><br><br>**signature**:<br>Function() => void | Function | (items, ref) => &lt;ul ref={ref}>{items}&lt;/ul> |
| threshold | height of threshold | Number | 100 |
| itemSizeGetter | get item's height<br><br>**signature**:<br>Function() => void | Function | - |
| jumpIndex | set this to jump to the index you want, works only when you set itemSizeGetter | Number | 0 |
| jumpIndex | the index you want to jump to, set itemSizeGetter if the height of items vary | Number | 0 |
2 changes: 1 addition & 1 deletion docs/virtual-list/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@
| itemsRenderer | 父渲染函数,默认为 (items, ref) => <ul ref={ref}>{items}</ul><br><br>**签名**:<br>Function() => void | Function | (items, ref) => &lt;ul ref={ref}>{items}&lt;/ul> |
| threshold | 缓冲区高度 | Number | 100 |
| itemSizeGetter | 获取item高度的函数<br><br>**签名**:<br>Function() => void | Function | - |
| jumpIndex | 设置初始位置,需要设置 itemSizeGetter 才能生效 | Number | 0 |
| jumpIndex | 设置跳转位置,需要设置 itemSizeGetter 才能生效, 不设置认为元素等高并取第一个元素高度作为默认高 | Number | 0 |
19 changes: 12 additions & 7 deletions src/cascader/menu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,22 @@ export default class CascaderMenu extends Component {

scrollToSelectedItem () {
const { prefix, useVirtual, children } = this.props;
if (!children || children.length === 0) {
return;
}
const selectedIndex = children.findIndex(item => !!item.props.checked || !!item.props.selected || !!item.props.expanded);

if (selectedIndex === -1) {
return;
}

if (useVirtual) {
if (!children || children.length === 0) return;
const selectedIndex = children.findIndex(item => !!item.props.selected);
if (selectedIndex !== -1) {
const instance = this.refs.virtual.getInstance();
instance.scrollTo(selectedIndex);
}
const instance = this.refs.virtual.getInstance();
setTimeout(() => instance.scrollTo(selectedIndex), 0);
} else {
const itemSelector = `.${prefix}menu-item`;
const menu = findDOMNode(this.refs.menu);
const targetItem = menu.querySelector(`${itemSelector}.${prefix}expanded, ${itemSelector}.${prefix}selected`);
const targetItem = menu.querySelectorAll(itemSelector)[selectedIndex];
if (targetItem) {
menu.scrollTop = targetItem.offsetTop - Math.floor((menu.clientHeight / targetItem.clientHeight - 1) / 2) * targetItem.clientHeight;
}
Expand Down
28 changes: 21 additions & 7 deletions src/select/base.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Menu from '../menu';
import Overlay from '../overlay';
import zhCN from '../locale/zh-cn';
import DataStore from './data-store';
import VirtualList from '../virtual-list';
import { isSingle, filter, isNull, valueToSelectKey } from './util';

const { Popup } = Overlay;
Expand Down Expand Up @@ -104,6 +105,10 @@ export default class Base extends React.Component {
* 键盘上下键切换菜单高亮选项的回调
*/
onToggleHighlightItem: PropTypes.func,
/**
* 是否开启虚拟滚动模式
*/
useVirtual: PropTypes.bool,
// 自定义类名
className: PropTypes.any,
// children
Expand Down Expand Up @@ -378,10 +383,6 @@ export default class Base extends React.Component {
return null;
}

saveMenuRef = (ref) => {
this.menuRef = ref;
};

handleSelect() {

}
Expand All @@ -392,7 +393,7 @@ export default class Base extends React.Component {
* @param {object} props
*/
renderMenu() {
const { prefix, mode, autoWidth, locale, notFoundContent } = this.props;
const { prefix, mode, autoWidth, locale, notFoundContent, useVirtual } = this.props;
const { dataSource, highlightKey } = this.state;
const value = this.state.value;
let selectedKeys;
Expand All @@ -419,7 +420,6 @@ export default class Base extends React.Component {
}

const menuProps = {
ref: this.saveMenuRef,
children,
style: autoWidth ? { width: this.width } : { minWidth: this.width },
selectedKeys,
Expand All @@ -434,7 +434,21 @@ export default class Base extends React.Component {
className: menuClassName
};

return <Menu {...menuProps} />;
return (
useVirtual ?
<div className={`${prefix}select-menu-wrapper`} style={{position: 'relative'}}>
<VirtualList
itemsRenderer={(items, ref) => {
return (<Menu ref={c => {
ref(c);
this.menuRef = c;
}} {...menuProps}>{items}</Menu>);
}}>
{children}
</VirtualList>
</div> :
<Menu {...menuProps} />
);
}

/**
Expand Down
12 changes: 12 additions & 0 deletions src/select/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,18 @@
/* transform-origin: center 41.8%; // icon 图像中心 */
}

&-menu-wrapper {
max-height: 260px;
overflow: auto;
border: $popup-local-border-width $popup-local-border-style $popup-local-border-color;
border-radius: $popup-local-corner;
box-shadow: $popup-local-shadow;
#{$select-prefix}-menu {
max-height: none;
border: none;
}
}

/* 弹层 */
&-menu {
max-height: 260px;
Expand Down
16 changes: 13 additions & 3 deletions src/virtual-list/virtual-list.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export default class VirtualList extends Component {
*/
itemSizeGetter: PropTypes.func,
/**
* 设置跳转位置,需要设置 itemSizeGetter 才能生效
* 设置跳转位置,需要设置 itemSizeGetter 才能生效, 不设置认为元素等高并取第一个元素高度作为默认高
*/
jumpIndex: PropTypes.number,
className: PropTypes.string
Expand Down Expand Up @@ -153,7 +153,7 @@ export default class VirtualList extends Component {
el = el.parentElement;

switch (window.getComputedStyle(el).overflowY) {
case 'auto': case 'scroll': case 'overlay': return el;
case 'auto': case 'scroll': case 'overlay': case 'visible': return el;
}

return window;
Expand Down Expand Up @@ -338,14 +338,24 @@ export default class VirtualList extends Component {

getSizeOf(index) {
const { cache } = this;
const { itemSizeGetter } = this.props;
const { itemSizeGetter, jumpIndex } = this.props;

// Try the cache.
if (index in cache) {
return cache[index];
}
if (itemSizeGetter) {
return itemSizeGetter(index);
}

const height = Object.values(this.cache).pop();
if (!this.defaultItemHeight && jumpIndex > -1 && height) {
this.defaultItemHeight = height;
}

if (this.defaultItemHeight) {
return this.defaultItemHeight;
}
}

constrain(from, size, {children, minSize}) {
Expand Down
Loading

0 comments on commit 53964f7

Please sign in to comment.