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语法:

原文地址:https://www.cnblogs.com/djtao/p/6195148.html