内容简介:1.用户可输入用户名2.输入评论内容3.点击发布
功能展示 :
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; }复制代码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 以案例的形式,来分析用户思维、产品思维和工程思维
- 实操AI算法:K-Means用户分群应用案例
- iOS混合开发库(GICXMLLayout)布局案例分析(1)今日头条案例
- 17个云计算开源案例入围第三届中国优秀云计算开源案例评选
- Spring Boot 2.0 基础案例(十二):基于转账案例,演示事务管理操作
- 基于MNIST数据集实现2层神经网络案例实战-大数据ML样本集案例实战
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
PHP典型模块与项目实战大全
杨宇 / 清华大学出版社 / 2012-1 / 79.00元
《PHP典型模块与项目实战大全》以实战开发为原则,以PHP典型模块和项目开发为主线,通过12个高质量的PHP典型模块和6个PHP大型应用,向读者揭示了Web开发的整体结构,并详尽地介绍PHP开发与建站的技术要点。《PHP典型模块与项目实战大全》附带1张DVD,内容是作者为《PHP典型模块与项目实战大全》录制的全程多媒体语音教学视频及《PHP典型模块与项目实战大全》所涉及的源代码。《PHP典型模块与......一起来看看 《PHP典型模块与项目实战大全》 这本书的介绍吧!