用TypeScipt和AMD模块化理念实现React官方教程(三)静态页面

现在我们可以象用C#开发那样来开发React应用了,我们的目的就是将 React官方教程整个迁移到typescript上实现:

创建第一个组件

在IDE的新建项中,我们可以找到TypeScript JSX文件,扩展名为tsx,如图:
这里写图片描述
在js目录下创建如下文件:
CommentBox.tsx
现在我们不需要象原教程那样命名.js文件了。完全可以按类来命名文件,这就是发挥TypeScript中Type 的力量的时候了!
文件内容如下:

/// <reference path="../typings/react/react-global.d.ts"/>
export =CommentBox;
class CommentBox extends React.Component<any, any> {
    render() {
        return <div className="commentBox">我是一个评论框。 </div>;
    }
}

注意HTML元素我们用小写字母开头,而自定义的Ract类我们用大写字母开头。
另外创建如下文件作为主文件:
main.tsx
文件内容如下:

/// <reference path="../typings/react/react-global.d.ts"/>
import CommentBox = require("./CommentBox");
ReactDOM.render(<CommentBox />, document.getElementById('content'));

这时点按运行,不出意外的话,浏览器将显示正常结果,内容为:我是一个评论框。

组合组件

让我们跟随示例创建CommentList 和 CommentForm如下:

CommentList.tsx
文件内容如下:

/// <reference path="../typings/react/react-global.d.ts"/>
export =CommentList;
class CommentList extends React.Component<any, any> {
    render() {
        return <div className="commentList">你好,我是一个评论列表。</div>;
    }
}

CommentForm.tsx

文件内容如下:

/// <reference path="../typings/react/react-global.d.ts"/>
export =CommentForm;
class CommentForm extends React.Component<any, any> {
    render() {
        return <div className="commentForm">你好,我是一个评论表单。</div>;
    }
}

接下去修改CommentBox.tsx,如下:

/// <reference path="../typings/react/react-global.d.ts"/>
import CommentList = require("./CommentList");
import CommentForm = require("./CommentForm");
export =CommentBox;
class CommentBox extends React.Component<any, any> {
    render() {
        return (
            <div className="commentBox">
                <h1>评论</h1>
                <CommentList />
                <CommentForm />
            </div>
        );
    }
}

使用props

现在让我们他建Comment组件,它将使用从父组件那里传入的数据。从父组件那里传入的数据将作为”属性(propery)”存在于子组件中。这些属性(properties)通过this.props访问。使用props,我们可以从CommentList传入的数据读取到Comment中,将生成一些标记:

Comment.tsx
文件内容如下:

/// <reference path="../typings/react/react-global.d.ts"/>
export =Comment;
class Comment extends React.Component<any, any> {
    render() {
        return (
            <div className="comment">
                <h2 className="commentAuthor">
                    {this.props.author}
                    </h2>
                {this.props.children}
            </div>
        );
    }
}

组件属性

上面我们已经定义好了Comment 组件,我们想要将作者名字和评论文本传入。这样可以让我们为每个单独的评论重用想同的代码。现在让我们在CommentList中添加一些评论:
CommentList.tsx

/// <reference path="../typings/react/react-global.d.ts"/>
import Comment = require('./Comment');
export =CommentList;
class CommentList extends React.Component<any, any> {
    render() {
        return (
            <div className="commentList">
            <Comment author="Eureka Chen">这是其中一个评论</Comment>
            <Comment author="Jordan Walke">这是 *另一个* 评论</Comment>
            </div>
        );
    }
}

添加Markdown解析

在index.html我们引用了第三方的marked库,将Markdown文件转化为Html。将comment.tsx改写成:

/// <reference path="../typings/react/react-global.d.ts"/>
/// <reference path="../typings/marked/marked.d.ts"/>
export =Comment;
class Comment extends React.Component<any, any> {
    render() {
        return (
            <div className="comment">
                <h2 className="commentAuthor">
                    {this.props.author}
                </h2>
                { marked(this.props.children.toString())}
            </div>
        );
    }
}

注意在html中添加对maked.js的引用。
现在我们得到如图示的结果:
这里写图片描述

但是这里有个问题!从如图的输出中,直接输出了Html标签。我们需要他们生成Html。这是因为React防止XSS攻击,这里有个方法,但框架警告你不要这样。

/// <reference path="../typings/react/react-global.d.ts"/>
/// <reference path="../typings/marked/marked.d.ts"/>
export =Comment;
class Comment extends React.Component<any, any> {
    rawMarkup() {
        var rawMarkup = marked(this.props.children.toString(), { sanitize: true });
        return { __html: rawMarkup };
    }

    render() {
        return (
            <div className="comment">
                <h2 className="commentAuthor">
                    {this.props.author}
                </h2>
                <span dangerouslySetInnerHTML={this.rawMarkup() } />
            </div>
        );
    }
}

这是API特意让原生HTML难以插入,但marked可以利用这个后门。

挂接到数据模型

到现在我们是直接在源代码中插入评论。现在,让我们使用JSON数据插入评论中。最终这些数据会来自服务器,但现在,我们写在源码中:

我们在main.tsx中加入data,如下:

/// <reference path="../typings/react/react-global.d.ts"/>
import CommentBox = require("./CommentBox");
var data = [
    { id: 1, author: "Eureka Chen", text: "这是一个评论" },
    { id: 2, author: "Jordan Walke", text: "这是 *另一个* 评论" }
];

ReactDOM.render(<CommentBox data={data} />, document.getElementById('content'));

然后在CommentBox.tsx中改为:

/// <reference path="../typings/react/react-global.d.ts"/>
import CommentList = require("./CommentList");
import CommentForm = require("./CommentForm");
export =CommentBox;
class CommentBox extends React.Component<any, any> {
    render() {
        return (
            <div className="commentBox">
                <h1>评论</h1>
                <CommentList data={this.props.data} />
                <CommentForm />
            </div>
        );
    }
}

现在数据传到了CommentList,让我们动态生成评论,CommentList.tsx如下:

/// <reference path="../typings/react/react-global.d.ts"/>
import Comment = require('./Comment');
export =CommentList;
class CommentList extends React.Component<any, any> {
    render() {
        var commentNodes = this.props.data.map(
            function (comment) {
                return (
                    <Comment author={comment.author} key={comment.id}>
                    {comment.text}
                    </Comment>
                );
            });
        return (
            <div className="commentList">
                {commentNodes}
            </div>
        );
    }
}

最终结果如下:
这里写图片描述

下一次我们开始讲从服务器获取数据。

posted @ 2016-02-20 15:22  EurekaChen  阅读(470)  评论(0编辑  收藏  举报