我如何滚动div在ReactJS中可见?

我有一个popup列表,这是一个包含子div的垂直列表的div 。 我已经添加了向上/向下的键盘导航,以更改当前突出显示哪个孩子。

现在,如果我按下向下键足够多的时间,突出显示的项目不再可见。 如果视图滚动,则向上键也会发生同样的情况。

React将子div自动滚动到视图中的正确方法是什么?

我假设你有某种List组件和某种Item组件。 我在一个项目中做的方式是让项目知道它是否有效; 该项目将要求列表滚动到视图中,如有必要。 考虑下面的伪代码:

 class List extends React.Component { render() { return <div>{this.props.items.map(this.renderItem)}</div>; } renderItem(item) { return <Item key={item.id} item={item} active={item.id === this.props.activeId} scrollIntoView={this.scrollElementIntoViewIfNeeded} /> } scrollElementIntoViewIfNeeded(domNode) { var containerDomNode = React.findDOMNode(this); // Determine if `domNode` fully fits inside `containerDomNode`. // If not, set the container's scrollTop appropriately. } } class Item extends React.Component { render() { return <div>something...</div>; } componentDidMount() { this.ensureVisible(); } componentDidUpdate() { this.ensureVisible(); } ensureVisible() { if (this.props.active) { this.props.scrollIntoView(React.findDOMNode(this)); } } } 

更好的解决scheme可能是让列表负责将项目滚动到视图中(而不需要知道它甚至在列表中)。 要做到这一点,你可以添加ref属性到一个特定的项目,并find它:

 class List extends React.Component { render() { return <div>{this.props.items.map(this.renderItem)}</div>; } renderItem(item) { var active = item.id === this.props.activeId; var props = { key: item.id, item: item, active: active }; if (active) { props.ref = "activeItem"; } return <Item {...props} /> } componentDidUpdate(prevProps) { // only scroll into view if the active item changed last render if (this.props.activeId !== prevProps.activeId) { this.ensureActiveItemVisible(); } } ensureActiveItemVisible() { var itemComponent = this.refs.activeItem; if (itemComponent) { var domNode = React.findDOMNode(itemComponent); this.scrollElementIntoViewIfNeeded(domNode); } } scrollElementIntoViewIfNeeded(domNode) { var containerDomNode = React.findDOMNode(this); // Determine if `domNode` fully fits inside `containerDomNode`. // If not, set the container's scrollTop appropriately. } } 

如果您不想执行math运算来确定项目是否在列表节点中可见,那么可以使用DOM方法scrollIntoView()或Webkit特定的scrollIntoViewIfNeeded ,它具有可用的 scrollIntoViewIfNeeded ,因此您可以在非-Webkit浏览器。

要build立在@Michelle Tilley的答案,我有时想滚动,如果用户的select更改,所以我触发componentDidUpdate滚动。 我也做了一些math计算多远滚动,是否需要滚动,这对我来说如下所示:

  componentDidUpdate() { let panel, node; if (this.refs.selectedSection && this.refs.selectedItem) { // This is the container you want to scroll. panel = this.refs.listPanel; // This is the element you want to make visible w/i the container // Note: You can nest refs here if you want an item w/i the selected item node = ReactDOM.findDOMNode(this.refs.selectedItem); } if (panel && node && (node.offsetTop > panel.scrollTop + panel.offsetHeight || node.offsetTop < panel.scrollTop)) { panel.scrollTop = node.offsetTop - panel.offsetTop; } } 

另一个在ref中使用函数而不是string的例子

 class List extends React.Component { constructor(props) { super(props); this.state = { items:[], index: 0 }; this._nodes = new Map(); this.handleAdd = this.handleAdd.bind(this); this.handleRemove = this.handleRemove.bind(this); } handleAdd() { let startNumber = 0; if (this.state.items.length) { startNumber = this.state.items[this.state.items.length - 1]; } let newItems = this.state.items.splice(0); for (let i = startNumber; i < startNumber + 100; i++) { newItems.push(i); } this.setState({ items: newItems }); } handleRemove() { this.setState({ items: this.state.items.slice(1) }); } handleShow(i) { this.setState({index: i}); const node = this._nodes.get(i); console.log(this._nodes); if (node) { ReactDOM.findDOMNode(node).scrollIntoView({block: 'end', behavior: 'smooth'}); } } render() { return( <div> <ul>{this.state.items.map((item, i) => (<Item key={i} ref={(element) => this._nodes.set(i, element)}>{item}</Item>))}</ul> <button onClick={this.handleShow.bind(this, 0)}>0</button> <button onClick={this.handleShow.bind(this, 50)}>50</button> <button onClick={this.handleShow.bind(this, 99)}>99</button> <button onClick={this.handleAdd}>Add</button> <button onClick={this.handleRemove}>Remove</button> {this.state.index} </div> ); } } class Item extends React.Component { render() { return (<li ref={ element => this.listItem = element }> {this.props.children} </li>); } } 

演示: https : //codepen.io/anon/pen/XpqJVe

在你的keyup / down处理程序中,你只需要设置你想要滚动的div的scrollTop属性,使其向下滚动(或向上)。

例如:

JSX:

<div ref="foo">{content}</div>

键盘/向下处理程序:

this.refs.foo.getDOMNode().scrollTop += 10

如果你做类似于上面的,你的div将向下滚动10个像素(假设div设置为auto溢出或者在CSS中scroll ,并且当然内容溢出)。

你将需要展开这个来find你想滚动div的滚动div内的元素的偏移量,然后修改scrollTop滚动足够远以显示基于它的高度的元素。

看看MDT的scrollTop的定义,并在这里offsetTop:

https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollTop

https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetTop

我只是为其他人在React中searchScroll-Tofunction添加一些信息。 我已经绑定了几个库来为我的应用程序执行Scroll-To,并且没有从我的用例中工作,直到findreact-scrollchor,所以我想我会传递它。 https://github.com/bySabi/react-scrollchor