• React.js入门笔记(再续):评论框的实现


    本案例来自React.js中文官网对应内容。

    一. 运行环境

    <link rel="stylesheet" type="text/css" href="css/css.css"/>
      <!-- 核心 -->
      <script src="js/react.js"></script>
      <!-- 加载dom方法 -->
      <script src="js/react-dom.js"></script>
      <!-- 将 JSX 语法转为 JavaScript 语法 -->
      <script src="js/browser.min.js"></script>
      <!-- jquery -->
      <script type="text/javascript" src="js/jquery-1.11.3.js"></script>
      <!--markdown渲染引擎-->
       <script type="text/javascript" src="js/remarkable.min.js"></script>
      <!-- 自身的javascript代码 -->
      <script type="text/javascript" src="js/js.js"></script>
    </head>
    

    二. 组件架构

    App下有两个子组件CommentList(评论列表)和CommentForm(评论区),其中CommentList下又有一个子组件Comment(评论)

    - App
      - CommentList
        - Comment
      - CommentForm
    

    Comment包括一个h2的评论人名称,一个span的评论内容,获取数据之后,Comment组件以数组的形式传入CommentList。

    三. 流动数据

    接下来就是把这5个组件写出来。

    // 最底层的组件Comment,隶属于CommentList
            var Comment=React.createClass({
                render:function(){
                    return (
    
                    );
                }
            });
    
            // 中层对象,包括CommentList和CommentForm
            var CommentList=React.createClass({
                render:function(){
                    return (
    
                    );
                }
            });
    
            var CommentForm=React.createClass({
                render:function(){
                    return (
    
                    );
                }
            });
    
            // 最高层对象App,包括两个中层组件
            var App=React.createClass({
                render:function(){
                    return (
    
                    );
                }
            });
    
            // 渲染模块
            ReactDOM.render(
                <App/>,
                document.getElementById('example')
            );
    

    数据通过props传入App,可以在html文件根目录下创建一个“json.json”文件:放入以下内容:

    [
      {"id": 1, "author": "小明", "text": "小明摸摸大"},
      {"id": 2, "author": "小红", "text": "小红萌萌哒"}
    ]
    

    所以我只要给App传递一个url即可。然后在文档插入之后执行jQuery的getJSON方法:最后在存入到App的state中。每次更新state,对会造成变化。
    既然state可以实时更新,那么不如设置一个定时器,每隔2s执行一次数据刷新。刷新间隔由App的props.timer传入。
    目前的组件变成了这样

    // 最底层的组件Comment,隶属于CommentList
            var Comment=React.createClass({
                render:function(){
                    return (
                        <li>
                            <h2>{this.props.author}</h2>
                            <span>{this.props.text}</span>
                        </li>
                    );
                }
            });
            //
            // 中层对象,包括CommentList和CommentForm
            var CommentForm=React.createClass({
                render:function(){
                    //console.log(this.props)
                    return (
                        <div></div>
                    );
                }
            });
    
            var CommentList=React.createClass({
                render:function(){
                    var arr=[];
    
                    this.props.data.map(function(item){
                        //console.log(item.author)
                        var content=
                        (
                            <Comment
                            author={item.author}
                            text={item.text}
                            key={item.id}/>
    
                        );
                        arr.push(content);
                    });
                    console.log(arr)
                    return (
                        <ul>{arr}</ul>
                    );
                }
            });
    
            // 最高层对象App,包括两个中层组件
            var App=React.createClass({
                getInitialState:function(){
                    return {
                        data:[]
                    };
                },
                loadServer:function(){
                    var _this=this;
                    $.getJSON(this.props.url,function(data){
                        _this.setState({
                            data:data
                        })
                    });
                },
                componentDidMount:function(){
                    console.log(this.props.timer)
                    var _this=this;
                    setInterval(function(){
                        _this.loadServer();
                    },_this.props.timer)
                },
                render:function(){
                    //console.log(this.state)
                    return (
                        <div>
                            <h1>当前评论</h1>
                            <CommentList data={this.state.data}/>
                            <CommentForm/>
                        </div>
                    );
                }
            });
    
            // 渲染模块
            ReactDOM.render(
                <App url="json.json" timer={2000}/>,
                document.getElementById('example')
            );
    

    数据就流动起来了。如果你修改了服务器,定时器会在2s后重新更新所得到的数据。

    四. markdown语法

    这部分主要是调用remarkable插件,渲染你看到的数据。而渲染自然是在底层的Comment组件上完成。
    所以我把Comment组件改成这样:

    // 最底层的组件Comment,隶属于CommentList
            var Comment=React.createClass({
                render:function(){
                    var md=new Remarkable();//调用插件
                    var commentContent=md.render(this.props.text.toString());//渲染获得的字符串!
                    return (
                        <li>
                            <h2>{this.props.author}</h2>
                            <span>{commentContent}</span>
                        </li>
                    );
                }
            });
    

    结果就搞笑了。纯文本在渲染引擎渲染之后变成了带P标签的内容。

    解决方案:再此需要一个官方定义的props——

    dangerouslySetInnerHTML
    

    实现方法如下:

    // 最底层的组件Comment,隶属于CommentList
            var Comment=React.createClass({
                getContent:function(){
                    var md=new Remarkable();//调用插件
                    var commentContent=md.render(this.props.text.toString());//渲染获得的字符串!
                    return ({
                        __html:commentContent
                    });//注意是两个下划线!
                },
                render:function(){
    
                    return (
                        <li>
                            <h2>{this.props.author}</h2>
                            <span dangerouslySetInnerHTML={this.getContent()}/>
                        </li>
                    );
                }
            });
    

    五.添加新评论

    到目前为止一切看起来还算简单。现在需要加新的评论。
    CommentForm添加的是一个新的表单。里面包含了评论的大名,评论内容,还有提交按钮。

    var CommentForm=React.createClass({
                render:function(){
                    //console.log(this.props)
                    return (
                        <form>
                            <input type="text" placeholder="你的大名"/><br/>
                            <textarea type="text" placeholder="评论内容"></textarea><br/>
                            <button type="submit">提交</button>
                        </form>
                    );
                }
            });
    

    在实现这个组件的时候,需要考虑它的状态。文本框的内容显然是状态。所以用一个state来保存它的状态。输入一次就保存一次并返回到文本框的value之中。

    var CommentForm=React.createClass({
                getInitialState:function(){
                    return ({
                        author:"",
                        text:""
                    });
                },//初始化状态
                authorChange:function(e){
                    this.setState({
                        author:e.target.value
                    });
                },
                textChange:function(e){
                    this.setState({
                        text:e.target.value
                    })
                },
                render:function(){
                    //console.log(this.props)
                    return (
                        <form>
                            <input
                              type="text"
                              placeholder="你的大名"
    						  value={this.state.author}
                              onChange={this.authorChange}/><br/>
                            <textarea type="text"
                              placeholder="评论内容"
    						  value={this.state.text}
                              onChange={this.textChange}></textarea><br/>
                            <button type="submit">提交</button>
                        </form>
                    );
                }
            });
    

    组件已经变得很长很长,但是基本上也不需要想什么。

    提交表单

    提交表单做三件事,onSubmit在form标签上。

    • 阻止跳转(e.preventDefault)
    • 清空form的内容
    • 返回到服务器并刷新列表
    <form onSubmit={this.submit}>...
    

    submit函数:

    ...
    submit:function(e){
                    e.preventDefault();
                    // 接下来格式化获取内容!注意去掉评论头尾的空格。
                    var authorStr=this.state.author.trim();
                    var textStr=this.state.text.trim();
                    if(!textStr||!authorStr){
                        alert('你有地方忘了填!');
                        return false;
                    }//简单的表单校验
    
                    this.setState({
                        author:'',
                        text:''
                    });//清空表单内容
    
                },
    			...
    

    这就实现了前两步,但是提交到服务器并刷新好像用前端的方法无法实现。
    我们之前做了每隔两秒钟刷新一次,所以每次都要拿数据,在这个案例中不现实。
    所以为了不涉及太多无关知识,把定时器拿掉。

    先不理它,还是做回调函数,把状态反馈到App:并刷新App的state:
    返回的callback应该包括评论人名字,评论内容,说白了就是把这个对象扔进去作为参数。
    那么id值呢?就用一个Data对象给他生成吧!(Date.now())

    // 最底层的组件Comment,隶属于CommentList
            var Comment=React.createClass({
                getContent:function(){
                    var md=new Remarkable();//调用插件
                    var commentContent=md.render(this.props.text.toString());//渲染获得的字符串!
                    return ({
                        __html:commentContent
                    });//注意是两个下划线!
                },
                render:function(){
                    return (
                        <li>
                            <h2>{this.props.author}</h2>
                            <span dangerouslySetInnerHTML={this.getContent()}/>
                        </li>
                    );
                }
            });
            //
            // 中层对象,包括CommentList和CommentForm
            var CommentForm=React.createClass({
                getInitialState:function(){
                    return ({
                        author:"",
                        text:""
                    });
                },//初始化状态
                authorChange:function(e){
                    this.setState({
                        author:e.target.value,
                    });
    
                },
                textChange:function(e){
                    this.setState({
                        text:e.target.value,
                    })
    
                },
                submit:function(e){
                    e.preventDefault();
                    // 接下来格式化获取内容!注意去掉评论头尾的空格。
                    var authorStr=this.state.author.trim();
    
                    var textStr=this.state.text.trim();
                    if(!textStr||!authorStr){
                        alert('你有地方忘了填!');
                        return false;
                    }//简单的表单校验
                    this.props.callback({
                        "author":authorStr,
                        "text":textStr
                    });// 提交到服务器!
                    this.setState({
                        author:'',
                        text:''
                    });//清空表单内容
    
                },
                render:function(){
                    //console.log(this.props)
                    return (
                        <form onSubmit={this.submit}>
                            <input
                              type="text"
                              placeholder="你的大名"
                              value={this.state.author}
                              onChange={this.authorChange}/><br/>
                            <textarea type="text"
                              placeholder="评论内容"
                              value={this.state.text}
                              onChange={this.textChange}></textarea><br/>
                            <button type="submit">提交</button>
                        </form>
                    );
                }
            });
    
            var CommentList=React.createClass({
                render:function(){
                    var arr=[];
    
                    this.props.data.map(function(item){
    
                        var content=
                        (
                            <Comment
                            author={item.author}
                            text={item.text}
                            key={item.id}/>
    
                        );
                        arr.push(content);
                    });
    
                    return (
                        <ul>{arr}</ul>
                    );
                }
            });
    
            // 最高层对象App,包括两个中层组件
            var App=React.createClass({
                getInitialState:function(){
                    return {
                        data:[]
                    };
                },
                loadServer:function(){
                    var _this=this;
                    $.getJSON(this.props.url,function(data){
                        _this.setState({
                            data:data
                        })
                    });
                },
                componentDidMount:function(){
                    this.loadServer();
                    // 服务器环境设置
                    // var _this=this;
                    // setInterval(function(){
                    //     _this.loadServer();
                    // },_this.props.timer)
                },
                refreshComment:function(comment) {
                    console.log(comment)//假设已经提交了
                    comment.id=Date.now()//给他一个id值!
                    var newComments=this.state.data.concat([comment]);//把它桥接起来!
                    console.log(newComments)
                    // 接下来再获取一次。
    
                    // 服务器环境下可以这样做
                    // $.ajax({
                    //   url: this.props.url,
                    //   dataType: 'json',
                    //   type: 'POST',
                    //   data: comment,
                    //   success: function(data) {
                    //     //console.log(data)
                    //     this.setState({data: data});
                    //   }.bind(this),
                    //   error: function(xhr, status, err) {
                    //     console.error(this.props.url, status, err.toString());
                    //   }.bind(this)
                    // });
    
                    //非服务器环境设置一个新状态就可以了。
                    this.setState({
                        data:newComments
                    })
               },
                render:function(){
                    //console.log(this.state)
                    return (
                        <div>
                            <h1>当前评论</h1>
                            <CommentList data={this.state.data}/>
                            <CommentForm callback={this.refreshComment}/>
                        </div>
                    );
                }
            });
    
            // 渲染模块
            ReactDOM.render(
                <App url="json.json" timer={2000}/>,
                document.getElementById('example')
            );
    

    效果支持简单的markdown语法:

  • 相关阅读:
    VMware下桥接设置
    oracle 当行函数
    oracle基于scott用户的经典sql 面试题(一)
    java 公平打乱数组顺序 重新排列
    学习.NET3中
    坚持
    分组小计合计报表的SQL
    使用ObjectDataSource注意DeleteMethod、UpdateMethod、Insert等方法中参数的命名约定
    SQL语句like子句中的转义符
    Oracle数据迁移:从存储了中文的但字符集为WE8ISO8859P1数据库导入数据到字符集为ZHS16GBK的数据库
  • 原文地址:https://www.cnblogs.com/djtao/p/6195148.html
Copyright © 2020-2023  润新知