React 小案例 用户评论

栏目: IOS · Android · 发布时间: 7年前

内容简介:1.用户可输入用户名2.输入评论内容3.点击发布

功能展示 :

1.用户可输入用户名

2.输入评论内容

3.点击发布

4.用户名和用户评论会被显示在列表里,第一个评论在最上面

5.且显示本条评论离现在过去了多长时间

6.鼠标放在事件上方可显示删除键,点击删除,删除当前

React 小案例 用户评论

总体结构:

1.components下创建comment文件夹

2.先创建用户输入组件:CommentInput

3.再创建单条用户评论视图:Comment

4.接着创建CommentList组件,将用户评论遍历渲染成评论列表

5.创建CommentApp组件,将CommentInput评论组件和CommentList列表组件渲染到一起

6.再index.js中引入展示

React 小案例 用户评论

用户输入组件: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;
}复制代码

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。

Effective JavaScript

Effective JavaScript

David Herman / Addison-Wesley Professional / 2012-12-6 / USD 39.99

"It's uncommon to have a programming language wonk who can speak in such comfortable and friendly language as David does. His walk through the syntax and semantics of JavaScript is both charming and h......一起来看看 《Effective JavaScript》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试