功能展示 :
1.使用者可輸入使用者名稱
2.輸入評論內容
3.點選發布
4.使用者名稱和使用者評論會被顯示在列表裡,第一個評論在最上面
5.且顯示本條評論離現在過去了多長時間
6.滑鼠放在事件上方可顯示刪除鍵,點選刪除,刪除當前
總體結構:
1.components下建立comment資料夾
2.先建立使用者輸入元件:CommentInput
3.再建立單條使用者評論檢視:Comment
4.接著建立CommentList元件,將使用者評論遍歷渲染成評論列表
5.建立CommentApp元件,將CommentInput評論元件和CommentList列表元件渲染到一起
6.再index.js中引入展示
使用者輸入元件:CommentInput 所有內容
1.建立使用者名稱輸入檢視模板,
用ref獲取input此DOM節點的值,
import {Component} from "react";
import React from "react";
class CommentInput extends Component{
constructor(){
super();
this.state={
//使用者名稱
username:'',
//評論內容
content:''
}
}
//監聽使用者輸入使用者名稱事件
handleUsernameChange=(event)=>{
this.setState({
username:event.target.value
})
};
//監聽使用者輸入評論事件
handleContentChange=(event)=>{
this.setState({
content:event.target.value
})
};
//點選發布事件
handleSubmit=()=>{
if(this.props.submit){
this.props.submit({
username:this.state.username,
content:this.state.content,
createTime:+new Date()
})
}
//點選發布後將state中的評論區域重新至為空
this.setState({
content:''
})
};
//使用者名稱框失去焦點
handleUsernameHold=(event)=>{
//將使用者名稱資料儲存到本地
localStorage.setItem('username',event.target.value)
};
//將要裝載,在render之前呼叫;
componentWillMount(){
//改變資料重新渲染前get獲取使用者名稱
const username=localStorage.getItem('username');
if(username){
this.setState({username})
}
}
//(裝載完成),在render之後呼叫
componentDidMount(){
//使用者重新整理之後,使用者名稱輸入自動獲取焦點
this.input.focus();
};
render(){
return(
<div className='comment-input'>
<div className='comment-field'>
<span className='comment-field-name'>使用者名稱:</span>
<div className='comment-field-input'>
<input
ref={(input)=>this.input=input}
value={this.state.username}
onBlur={this.handleUsernameHold}
onChange={this.handleUsernameChange}
/>
</div>
</div>
<div className='comment-field'>
<span className='comment-field-name'>評論內容:</span>
<div className='comment-field-input'>
<textarea
value={this.state.content}
onChange={this.handleContentChange}
/>
</div>
</div>
<div className='comment-field-button'>
<button onClick={this.handleSubmit}>
釋出
</button>
</div>
</div>
)
}
}
export default CommentInput//給input標籤繫結 ref={(input)=>{this.input = input}}
//用來直接獲取dom節點的值,此處將input的值賦給this.input,讓外部能訪問
複製程式碼
單條使用者評論檢視:Comment 所有內容
import {Component} from "react";
import React from "react";
class Comment extends Component{
constructor(){
super();
this.state ={
//初始化時間
timeString:''
}
}
//顯示使用者評論時間
handleTimeString=()=>{
const item=this.props.item;
//當前時間減去使用者建立時的時間
const duration=(+Date.now()-item.createTime)/1000;
//如果足夠60就轉成分,不夠60就轉成秒
return duration>60?`${Math.round(duration/60)}分鐘前`:`${Math.round(Math.max(duration,1))}秒前`;
};
//點選刪除事件
//將handleDelete事件傳出,index傳出
handleDelete=()=>{
if(this.props.deleteItem){
this.props.deleteItem(this.props.index)
}
};
render(){
return(
<div className='comment'>
<div className='comment-user'>
<span className='comment-username'>{this.props.item.username} </span>:
</div>
<p>{this.props.item.content}</p>
<span className="comment-delete" onClick={this.handleDelete}>刪除</span>
<span className="comment-createdtime">
{this.handleTimeString()}
</span>
</div>
)
}
}
export default Comment複製程式碼
評論列表 CommentList 所有內容
import {Component} from "react";
import React from "react";
import Comment from './Comment'
class CommentList extends Component{
constructor(){
super();
this.state ={
items:[]
}
}
//將陣列列表傳出,將deleteItem刪除事件傳出
render(){
return(
<div>
{this.props.items.map((item,index)=>
<Comment deleteItem={this.props.deleteItem}
item={item} index={index} key={index}
/>)}
</div>
)
}
}
export default CommentList複製程式碼
總元件CommentApp 的所有內容
import {Component} from "react";
import React from "react";
import CommentInput from './CommentInput'
import CommentList from './CommentList'
class CommentApp extends Component{
constructor(){
super();
this.state ={
items:[]
}
}
//點選傳送
handleSubmit=(item)=>{
//點選傳送時push當前那條
this.state.items.push(item);
//更新資料列表
this.setState({
items:this.state.items
});
//使用者重新整理時儲存當前資料
localStorage.setItem('items',JSON.stringify(this.state.items))
};
//刪除事件
handleDelete=(index)=>{
console.log(index);
//點選刪除,刪除當前
this.state.items.splice(index,1);
//列表資料更新至最新
this.setState({
items:this.state.items
});
//刪除後儲存當下資料
localStorage.setItem('items',JSON.stringify(this.state.items))
};
//裝載前獲取
componentWillMount(){
let items=localStorage.getItem('items');
if(items){
items=JSON.parse(items);
this.setState({items})
}
};
render(){
return(
<div className="wrapper">
<CommentInput submit={this.handleSubmit} />
<CommentList deleteItem={this.handleDelete} items={this.state.items}/>
</div>
)
}
}
export default CommentApp
// window.localStorage
// 儲存資料語法:
// localStorage.setItem("key", "value");
// 讀取資料語法:
// var lastname = localStorage.getItem("key");
// 刪除資料語法:
// localStorage.removeItem("key");複製程式碼
index.js下所有內容:
import React from 'react';
import ReactDOM from 'react-dom';
import CommentApp from "./components/comment/CommentApp";
import './index.css'
ReactDOM.render(<CommentApp/>, document.getElementById('root'));
複製程式碼
index.css下所有樣式內容:
body {
margin: 0;
padding: 0;
font-family: sans-serif;
background-color: #fbfbfb;
}
.wrapper {
width: 500px;
margin: 10px auto;
font-size: 14px;
background-color: #fff;
border: 1px solid #f1f1f1;
padding: 20px;
}
/* 評論框樣式 */
.comment-input {
background-color: #fff;
border: 1px solid #f1f1f1;
padding: 20px;
margin-bottom: 10px;
}
.comment-field {
margin-bottom: 15px;
display: flex;
}
.comment-field .comment-field-name {
display: flex;
flex-basis: 100px;
font-size: 14px;
}
.comment-field .comment-field-input {
display: flex;
flex: 1;
}
.comment-field-input input,
.comment-field-input textarea {
border: 1px solid #e6e6e6;
border-radius: 3px;
padding: 5px;
outline: none;
font-size: 14px;
resize: none;
flex: 1;
}
.comment-field-input textarea {
height: 100px;
}
.comment-field-button {
display: flex;
justify-content: flex-end;
}
.comment-field-button button {
padding: 5px 10px;
width: 80px;
border: none;
border-radius: 3px;
background-color: #00a3cf;
color: #fff;
outline: none;
cursor: pointer;
}
.comment-field-button button:active {
background: #13c1f1;
}
/* 評論列表樣式 */
.comment-list {
background-color: #fff;
border: 1px solid #f1f1f1;
padding: 20px;
}
/* 評論元件樣式 */
.comment {
position: relative;
display: flex;
border-bottom: 1px solid #f1f1f1;
margin-bottom: 10px;
padding-bottom: 10px;
min-height: 50px;
}
.comment .comment-user {
flex-shrink: 0;
}
.comment-username {
color: #00a3cf;
font-style: italic;
}
.comment-createdtime {
padding-right: 5px;
position: absolute;
bottom: 0;
right: 0;
padding: 5px;
font-size: 12px;
}
.comment:hover .comment-delete {
color: #00a3cf;
}
.comment-delete {
position: absolute;
right: 0;
top: 0;
color: transparent;
font-size: 12px;
cursor: pointer;
}
.comment p {
margin: 0;
/*text-indent: 2em;*/
}
code {
border: 1px solid #ccc;
background: #f9f9f9;
padding: 0px 2px;
}複製程式碼