代码展示:
import { createContext, useContext, useRef, useState } from 'react';
import _ from 'lodash';
import './bilibili-review.scss';
import avatar from './images/bozai.png';
const defaultList = [
{
rpid: 3,
user: {
uid: '13258165',
avatar: 'https://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/reactbase/comment/zhoujielun.jpeg',
uname: '周杰伦'
},
content: '哎哟,不错哦',
ctime: '2023-10-18 08:15',
like: 98,
action: 0
},
{
rpid: 2,
user: {
uid: '36080105',
avatar: 'https://yjy-teach-oss.oss-cn-beijing.aliyuncs.com/reactbase/comment/xusong.jpeg',
uname: '许嵩'
},
content: '我寻你千百度 日出到迟暮',
ctime: '2023-11-13 11:29',
like: 88,
action: 2
},
{
rpid: 1,
user: {
uid: '30009257',
avatar,
uname: '黑马前端'
},
content: '学前端就来黑马',
ctime: '2023-10-19 09:00',
like: 66,
action: 1
}
];
const user = {
uid: '30009257',
avatar,
uname: '黑马前端'
};
const MsgContext = createContext();
const HeaderTab = ({ list, updateList }) => {
const tabOptions = [
{ type: 'latest', text: '最新' },
{ type: 'hottest', text: '最热' }
];
let [activeTab, setActiveTab] = useState('latest');
const updateActiveTab = (type) => {
setActiveTab(type);
updateList(type);
};
return (
<div className="header align-center">
<div className="title align-center">
评论<em>{list.length}</em>
</div>
<ul className="tab align-center">
{tabOptions.map((item, index) => {
return (
<li
className={`item align-center ${activeTab === item.type && 'active'}`}
key={item.type}
onClick={() => updateActiveTab(item.type)}>
<span>{item.text}</span>
{tabOptions.length - 1 !== index && <span className="split-line"></span>}
</li>
);
})}
{/*
// 多类名写法
// className={['item', 'align-center', activeTab === item.type ? 'active' : null].join(' ')}
// className={['item', 'align-center', activeTab === item.type && 'active'].join(' ')}
// className={`item align-center ${activeTab === item.type ? 'active' : null}`}
// className={`item align-center ${activeTab === item.type && 'active'}`}
*/}
</ul>
</div>
);
};
const PostReview = ({ updateList }) => {
const [content, setContent] = useState('');
const inputRef = useRef(null);
const addReviewItem = (e) => {
if (e.key === 'Enter') e.preventDefault();
if (!content) return alert('请输入评论!');
const time = new Date().toLocaleString();
const m_d = time.split(' ')[0].split('/');
const h_m = time.split(' ')[1].split(':');
h_m.pop();
const obj = {
rpid: new Date().getTime(),
user,
content,
ctime: `${m_d.join('-')} ${h_m.join('-')}`,
like: 0,
action: 0
};
updateList('add', '', obj);
setContent('');
inputRef.current.focus();
};
return (
<div className="post-review align-center">
<img src={user.avatar} alt={user.uname} className="avatar" />
<div className="input align-center">
<textarea
type="text"
ref={inputRef}
value={content}
onChange={(e) => setContent(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && addReviewItem(e)}
placeholder="发一条友善的评论"
/>
<button onClick={addReviewItem}>发布</button>
</div>
</div>
);
};
const ReviewItem = ({ item }) => {
const updateList = useContext(MsgContext);
return (
<div className="review-item">
<div className="left">
<img src={item.user.avatar} alt={item.user.uname} />
</div>
<div className="right">
<div className="user-name">{item.user.uname}</div>
<div className="content">{item.content}</div>
<div className="bottom">
<div className="time">{item.ctime}</div>
<div className="like-num">点赞数:{item.like}</div>
<ul className="controls">
{item.user.uid === user.uid && (
<li className="del" onClick={() => updateList('del', item.rpid)}>
删除
</li>
)}
</ul>
</div>
</div>
</div>
);
};
const ReviewList = ({ list }) => {
return (
<div className="review-list">
{list.map((item) => {
return <ReviewItem item={item} key={item.rpid} />;
})}
</div>
);
};
const App = () => {
const [list, setList] = useState(_.orderBy(defaultList, 'ctime', 'desc'));
const updateList = (type, id, newReview = {}) => {
let newList = [];
switch (type) {
case 'latest':
newList = _.orderBy(list, 'ctime', 'desc');
break;
case 'hottest':
newList = _.orderBy(list, 'like', 'desc');
break;
case 'del':
newList = list.filter((item) => item.rpid !== id);
break;
case 'add':
newList = [newReview, ...list];
break;
default:
newList = list;
break;
}
setList(newList);
};
return (
<div className="app">
<HeaderTab list={list} updateList={updateList} />
<div className="review-box">
<PostReview updateList={updateList} />
{/* 使用 context 机制实现跨层通信 */}
<MsgContext.Provider value={updateList}>
<ReviewList list={list} />
</MsgContext.Provider>
</div>
</div>
);
};
export default App;