将焦点放在 reactjs 中显示数组的最后一个元素
Set focus on the last element of a displayed array in reactjs
我正在使用 reactjs 编写一个聊天应用程序,我正在尝试弄清楚每次将新消息添加到数组时如何将焦点更改为最新消息。
我的反应聊天 window 看起来像这样:
<ChatHeader />
<Messages datas={this.state.datas} />
<ChatFooter sendMessage={this.sendMessage} />
我的消息组件如下所示:
var Messages = React.createClass({
render: function() {
// Loop through the list of messages and create array of Row components
var Rows = this.props.datas.map(function(data) {
return (
<Row username={data.username} message={data.message} />
)
});
return (
{Rows}
);
}
});
所以基本上每次我的主聊天 window 重新呈现时,我希望消息显示时列表一直向下滚动(显示最新的消息 - 或者 Rows 数组中的最后几件事) .我发现了一些关于转移焦点的问题,例如 ,但是当我尝试将焦点转移到消息时,它会将我带到列表的顶部。理想情况下,我想添加如下内容:
var Rows = this.props.datas.map(function(data) {
return (
<Row username={data.username} message={data.message} />
)
});
// Rows[Rows.length - 1].ref = "last";
这样我就可以专注于数组中的最后一个元素,但我一直无法找到一种方法来设置这样的引用。我见过的所有方式都显示在标签内设置引用。是否存在这样分配引用的方法?
我还考虑过给每一行一个唯一的 ID 号,并为每条新消息递增该编号,跟踪最大的数字,然后用它来引用最后一个元素,但似乎必须有更好的方法。实现此目标的最佳方法是什么?
我们将不得不利用 React 书中被认为是反模式的东西,并使用他们通常不赞成的 ReactDOM.findDOMNode
。
本质上,我们要做的是在 Messages class 上创建一个名为 onRowRender
的方法并将其绑定到 this
在 Messages 构造函数中。我们将使用 map
的可选第二个参数来跟踪生成了多少行,如果它是最后一行,我们将把 onRowRendered
方法传递给 Row 组件使用我们称之为 onRender
.
的道具
在每个 Row 组件的 componentDidMount
中,我们将检查 this.props.onRender
是否存在,如果存在则表示它是最后一个行所以我们调用 this.props.onRender
并传递给它 this
这是有问题的 Row 组件。
由于我们是在组件挂载后执行所有这些操作,这意味着我们将能够使用 ReactDOM.findDOMNode
获取该渲染组件的原始 javascript DOM 元素.我们在父 Messages class.
上创建的处理程序中执行此操作
说完所有这些之后,我们得到了有问题的 DOMNode 的顶部偏移量,我们还得到了它的 parentNode
然后将 parentNode
的 topOffset 设置为等于顶部偏移量。
注意:我在示例中使用了 es6 class 语法,但它也应该适用于 React.createClass。
class Messages extends React.Component {
constructor() {
super();
this.onRowRender = this.onRowRender.bind(this);
}
onRowRender(row) {
var rowDOM = ReactDOM.findDOMNode(row);
var offsets = rowDOM.getClientRects()[0];
var parent = rowDOM.parentNode;
parent.scrollTop = offsets.top;
}
render() {
return (
<div className='messages'>
{this.props.datas.map((data, i) => {
return (
<Row
key={data.key}
username={data.username}
message={data.message}
onRender={i === this.props.datas.length - 1 ? this.onRowRender : null}
/>
);
})}
</div>
);
}
}
class Row extends React.Component {
componentDidMount() {
if (this.props.onRender) this.props.onRender(this);
}
render() {
return (
<div>
{this.props.message} by: {this.props.username}
</div>
);
}
}
var datas = [
{
key: 1,
username: 'test user #1',
message: 'test message #1',
}, {
key: 2,
username: 'test user #2',
message: 'test message #2',
}, {
key: 3,
username: 'test user #3',
message: 'test message #3',
}, {
key: 4,
username: 'test user #4',
message: 'test message #4',
}, {
key: 5,
username: 'test user #5',
message: 'test message #5',
},
];
ReactDOM.render(
<Messages datas={datas} />,
document.getElementById('root')
);
强制性 jsfiddle:https://jsfiddle.net/69z2wepo/46701/
或者,您可以通过将 Rows 的 onRender
道具更改为 onRender={this.onRowRender}
然后将 onRowRender 更改为:
onRowRender(row) {
var rowDOM = ReactDOM.findDOMNode(row);
var parent = rowDOM.parentNode;
parent.scrollTop = parent.scrollHeight;
}
只要安装了新行,它就会滚动到底部。但是,按照我最初演示的方式进行操作,它将确保如果最后一个 Row 大于 Messages 组件的总高度它只会滚动到 行 的顶部,而不是整个列表的底部。 (我希望这是有道理的)
我正在使用 reactjs 编写一个聊天应用程序,我正在尝试弄清楚每次将新消息添加到数组时如何将焦点更改为最新消息。 我的反应聊天 window 看起来像这样:
<ChatHeader />
<Messages datas={this.state.datas} />
<ChatFooter sendMessage={this.sendMessage} />
我的消息组件如下所示:
var Messages = React.createClass({
render: function() {
// Loop through the list of messages and create array of Row components
var Rows = this.props.datas.map(function(data) {
return (
<Row username={data.username} message={data.message} />
)
});
return (
{Rows}
);
}
});
所以基本上每次我的主聊天 window 重新呈现时,我希望消息显示时列表一直向下滚动(显示最新的消息 - 或者 Rows 数组中的最后几件事) .我发现了一些关于转移焦点的问题,例如
var Rows = this.props.datas.map(function(data) {
return (
<Row username={data.username} message={data.message} />
)
});
// Rows[Rows.length - 1].ref = "last";
这样我就可以专注于数组中的最后一个元素,但我一直无法找到一种方法来设置这样的引用。我见过的所有方式都显示在标签内设置引用。是否存在这样分配引用的方法?
我还考虑过给每一行一个唯一的 ID 号,并为每条新消息递增该编号,跟踪最大的数字,然后用它来引用最后一个元素,但似乎必须有更好的方法。实现此目标的最佳方法是什么?
我们将不得不利用 React 书中被认为是反模式的东西,并使用他们通常不赞成的 ReactDOM.findDOMNode
。
本质上,我们要做的是在 Messages class 上创建一个名为 onRowRender
的方法并将其绑定到 this
在 Messages 构造函数中。我们将使用 map
的可选第二个参数来跟踪生成了多少行,如果它是最后一行,我们将把 onRowRendered
方法传递给 Row 组件使用我们称之为 onRender
.
在每个 Row 组件的 componentDidMount
中,我们将检查 this.props.onRender
是否存在,如果存在则表示它是最后一个行所以我们调用 this.props.onRender
并传递给它 this
这是有问题的 Row 组件。
由于我们是在组件挂载后执行所有这些操作,这意味着我们将能够使用 ReactDOM.findDOMNode
获取该渲染组件的原始 javascript DOM 元素.我们在父 Messages class.
说完所有这些之后,我们得到了有问题的 DOMNode 的顶部偏移量,我们还得到了它的 parentNode
然后将 parentNode
的 topOffset 设置为等于顶部偏移量。
注意:我在示例中使用了 es6 class 语法,但它也应该适用于 React.createClass。
class Messages extends React.Component {
constructor() {
super();
this.onRowRender = this.onRowRender.bind(this);
}
onRowRender(row) {
var rowDOM = ReactDOM.findDOMNode(row);
var offsets = rowDOM.getClientRects()[0];
var parent = rowDOM.parentNode;
parent.scrollTop = offsets.top;
}
render() {
return (
<div className='messages'>
{this.props.datas.map((data, i) => {
return (
<Row
key={data.key}
username={data.username}
message={data.message}
onRender={i === this.props.datas.length - 1 ? this.onRowRender : null}
/>
);
})}
</div>
);
}
}
class Row extends React.Component {
componentDidMount() {
if (this.props.onRender) this.props.onRender(this);
}
render() {
return (
<div>
{this.props.message} by: {this.props.username}
</div>
);
}
}
var datas = [
{
key: 1,
username: 'test user #1',
message: 'test message #1',
}, {
key: 2,
username: 'test user #2',
message: 'test message #2',
}, {
key: 3,
username: 'test user #3',
message: 'test message #3',
}, {
key: 4,
username: 'test user #4',
message: 'test message #4',
}, {
key: 5,
username: 'test user #5',
message: 'test message #5',
},
];
ReactDOM.render(
<Messages datas={datas} />,
document.getElementById('root')
);
强制性 jsfiddle:https://jsfiddle.net/69z2wepo/46701/
或者,您可以通过将 Rows 的 onRender
道具更改为 onRender={this.onRowRender}
然后将 onRowRender 更改为:
onRowRender(row) {
var rowDOM = ReactDOM.findDOMNode(row);
var parent = rowDOM.parentNode;
parent.scrollTop = parent.scrollHeight;
}
只要安装了新行,它就会滚动到底部。但是,按照我最初演示的方式进行操作,它将确保如果最后一个 Row 大于 Messages 组件的总高度它只会滚动到 行 的顶部,而不是整个列表的底部。 (我希望这是有道理的)