我需要将聊天滚动到第一条未读消息。 我有父组件MessagesList,其中包含map函数内的childComponent。 我需要深入研究并从那里获得具有属性的第一个未读元素(item.status ===“ new”) 在componentDidMount内部的MessagesList中,我需要使用
componentDidMount() {
this.scrollToFirstUnreadMessage()
}
scrollToFirstUnreadMessage = () => {
let firstUnreadElement = document.querySelector('.MessagesItem__root__support_new, .MessagesItem__root__writer_new');
let valueToScroll = (firstUnreadElement && firstUnreadElement.offsetTop) - 360;
let listContainer = this.listRef.current;
console.log(listContainer);
if(valueToScroll > 0) {
listContainer.scrollTop = valueToScroll;
} else {
listContainer.scrollTop = listContainer.scrollHeight;
}
}
此JS行的主要问题:
let firstUnreadElement = document.querySelector('.MessagesItem__root__support_new, .MessagesItem__root__writer_new');
如何通过反应仪器获得该元素。 并在此处发布两个组件:
import React, {Component} from "react";
import { debounce } from "lodash";
import MessagesItem from "../MessagesItem";
import css from "./MessagesList.styl";
export default class MessagesList extends Component {
static propTypes = {
};
constructor (props) {
super(props);
this.listRef = React.createRef();
this.state = {
listHeight: 0
}
this.state.itemIndex = 0;
}
componentDidMount() {
this.scrollToFirstUnreadMessage()
}
scrollToFirstUnreadMessage = () => {
let firstUnreadElement = document.querySelector('.MessagesItem__root__support_new, .MessagesItem__root__writer_new');
let valueToScroll = (firstUnreadElement && firstUnreadElement.offsetTop) - 360;
let listContainer = this.listRef.current;
console.log(listContainer);
if(valueToScroll > 0) {
listContainer.scrollTop = valueToScroll;
} else {
listContainer.scrollTop = listContainer.scrollHeight;
}
}
listHasScrolledToBottom = () => {
let listContainer = this.listRef.current;
if (listContainer.scrollHeight === listContainer.scrollTop + listContainer.offsetHeight) return true;
}
hasVerticalScrollbar = () => {
let listContainer = this.listRef.current;
if (listContainer.scrollHeight > listContainer.clientHeight) return true;
}
/**
* Sort messages
* @param messages
* @returns {*}
*/
sortMessages = (list) => {
list.sort(function (a, b) {
return new Date( b.sended ).getTime() - new Date( a.sended ).getTime();
});
return list;
}
onMouseEnter = (e) => {
if (!this.hasVerticalScrollbar()) {
this.props.markAllOnScrollToBottom(true);
}
}
onScroll = (e) => {
if (this.listRef.current.scrollTop === 0 && this.props.supportNextPage) {
let oldListHeight = this.listRef.current.scrollHeight;
setTimeout( function () {
let newListHeight = this.listRef.current.scrollHeight;
this.listRef.current.scrollTop = newListHeight - oldListHeight;
}.bind( this ), 100 );
this.props.getMessages(this.props.currentProcess);
}
if(this.listHasScrolledToBottom()) {
this.props.markAllOnScrollToBottom(true, this.props.currentProcess);
}
}
/**
* Added today and yesterday separator items
* @param messages
* @returns {Array}
*/
formatMessages = (list) => {
var today = new Date();
today.setHours(0);
today.setMinutes(0);
today.setSeconds(0);
var yesterday = new Date();
yesterday.setHours(0);
yesterday.setMinutes(0);
yesterday.setSeconds(0);
yesterday.setDate(today.getDate() - 1);
var laterList = [];
var yesterdayList = [];
var todayList = [];
for (var i = 0; i < list.length; i++) {
if (new Date( list[i].sended ).getTime() < (yesterday.getTime() / 1000)) {
laterList.push(list[i]);
// console.log("later");
} else if (new Date( list[i].sended ).getTime() < (today.getTime() / 1000)) {
yesterdayList.push(list[i]);
// console.log("yesterday");
} else {
todayList.push(list[i]);
// console.log("today");
}
}
var result = [];
if (laterList.length) {
result = laterList;
}
if (yesterdayList.length) {
if (result.length) {
result.push({yesterday: true, id: 'yesterday'});
}
result = result.concat(yesterdayList);
}
if (todayList.length) {
if (result.length) {
result.push({today: true, id: 'today'});
}
result = result.concat(todayList);
}
return result;
}
/**
* Prepare messages (sort and format)
* @param messages
* @returns {Array.<T>}
*/
prepareMessages = (list) => {
list = this.sortMessages(list);
list = list.reverse();
return this.formatMessages(list);
}
render () {
const { list } = this.props;
return (
<ul
className={css.root}
ref={this.listRef}
onScroll={ debounce(this.onScroll,100) }
onMouseEnter={ this.onMouseEnter }
>
{
list &&
this.prepareMessages(list).map((item, index) => {
if (item.today) {
return (
<div key="today" className="text-center message-day">
<span className="message-day-text">{this.props.t.today}</span>
</div>
);
}
if (item.yesterday) {
return (
<div key="yesterday" className="text-center message-day">
<span className="message-day-text">{this.props.t.yesterday}</span>
</div>
);
}
return (
<MessagesItem
key={index}
item={item}
/>
);
})
}
</ul>
)
}
}
import React, {Component} from "react";
import PropTypes from 'prop-types';
import classNames from 'classnames';
import css from "./MessagesItem.styl"
export default class MessagesItem extends Component {
static propTypes = {
item: PropTypes.shape({
msg: PropTypes.string,
message_type: PropTypes.string,
id: PropTypes.number,
status: PropTypes.string,
sender_name: PropTypes.string,
sended: PropTypes.string
}).isRequired
};
constructor(props) {
super(props);
this.itemRef = React.createRef();
}
render () {
const { item } = this.props;
let formattedTimeOptions = { year: 'numeric', month: 'long', day: 'numeric'};
let formattedTimeVal = new Date( item.sended ).toLocaleDateString(this.props.locale, formattedTimeOptions);
return (
<li
ref= { this.itemRef }
key= { item.id }
// isOnViewport = {this.isOnViewport}
className={classNames(css.root, {
[css.root__support_new]: item.status === "new" && item.message_type === "support_customer",
[css.root__writer_new]: item.status === "new" && item.message_type === "writer_customer",
[css.root__read]: item.status === "read"
})}
>
<div className={classNames(css.root__content, {
[css.root__content__left] : item.message_type === "support_customer",
[css.root__content__left_writer] : item.message_type === "writer_customer",
[css.root__content__right] : item.message_type === "customer_support" || item.message_type === "customer_writer",
})}>
<div className={css.root__author}>
<div className={css.root__name}>{item.sender_name}</div>
<div className={css.root__date}>{formattedTimeVal}</div>
</div>
<div className={css.root__message}>{item.msg}</div>
</div>
</li>
)
}
}
请不要对初中坚强:)