• React评论展示案例(包含知识点:state、props、ref、React声明周期、localStorage本地存储等)


    本案例在上一篇的案例(React组件之间通过Props传值的技巧(小案例,帮助体会理解props、state、受控组件和非受控组件等))的基础上加强功能和用户体验,但是当然还有很多需要改进的地方,后期一步步慢慢增强:

    import React,{Component} from 'react';
    import {render} from 'react-dom';
    import './index.css';
    
    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()
                })
            }
            this.setState({
                content:''
            })
        };
    
        handleUsernameHold=(event)=>{
            localStorage.setItem('username',event.target.value)
        };
    
        componentWillMount(){
            const username=localStorage.getItem('username');
            if(username){
                this.setState({username})
            }
        }
    
        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>
            )
        }
    }
    
    class CommentList extends Component{
    
        constructor(){
            super();
            this.state={
                items:[]
            }
        }
    
        render(){
            return(
                <div>
                    {this.props.items.map((item,index)=><Comment deleteItem={this.props.deleteItem} item={item} index={index} key={index}/>)}
                </div>
            )
        }
    }
    
    class Comment extends Component{
        constructor(){
            super();
            this.state={
                timeString:''
            }
        }
    
        handleTimeString=()=>{
            const item=this.props.item;
            const duration=(+Date.now()-item.createTime)/1000;
            return duration>60?`${Math.round(duration/60)}分钟前`:`${Math.round(Math.max(duration,1))}秒前`;
        };
    
        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>
            )
        }
    }
    
    class CommentApp extends Component{
        constructor(){
            super();
            this.state={
                items:[]
            }
        }
    
        handleSubmit=(item)=>{
            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>
            )
        }
    }
    
    class Index extends Component{
        render(){
            return(
                <div>
                    <CommentApp/>
                </div>
            )
        }
    }
    
    render(<Index/>,document.getElementById('root'));
    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;
    }
  • 相关阅读:
    vite的使用
    webpack--Plugin
    webpack--loader
    uniapp 或小程序,通过蓝牙连接设备, 给设备配网
    每一项与之前一项相加
    vue使用vue-fullpage
    React基礎
    无间隙循环轮播效果
    Wow.js动画效果
    正则表达式
  • 原文地址:https://www.cnblogs.com/Scar007/p/8081212.html
Copyright © 2020-2023  润新知