React开发项目例子

一、需求

1.分析:用react开发一个类似bootstrap4中的card组件http://v4-alpha.getbootstrap.com/components/card/,界面类似如下:

2.确定发目标:

3.确定开发顺序

4.开发流程介绍

测试采用TDD

二、代码

1.Card.js

 1 var React = require('react/addons');
 2 
 3 var Card = React.createClass({
 4     getInitialState: function() {
 5         return this.props.content;
 6     },
 7     handleClick: function() {
 8         this.setState({
 9             blocks : [{
10                 title: "Allen Iverson(已关注)",
11                 subtitle: "PG",
12                 text: "Cool player",
13                 links: [{
14                     url:"http://www.163.com",
15                     name:"链接1"
16                 }, {
17                     url:"http://www.g.cn",
18                     name:"链接2"
19                 }
20                 ]
21             }]
22         })
23     },
24     render: function(){
25         var content = this.state;
26 
27         var blocks = [];
28         for(var i = 0; i < content.blocks.length; i++){
29             var block = content.blocks[i];
30             var links = [];
31             for(var i = 0; i < block.links.length; i++){
32                 links.push(<a onClick={this.handleClick} className="card-link" href={block.links[i].url}>{block.links[i].name}</a>);
33             }
34             blocks.push(<div className="card-block">
35                         <h4 className="card-title">{block.title}</h4>
36                         <h6 className="card-subtitle">{block.subtitle}</h6>
37                         <p className="card-text">{block.text}</p>
38                         <p>
39                             {links}
40                         </p>
41                     </div>
42                 );
43         }
44 
45         var listGroup = [];
46         for(var i = 0; i < content.listGroup.length; i++){
47             listGroup.push(<li className="list-group-item">{content.listGroup[i]}</li>);
48         }
49 
50         var option = this.props.option ? "card text-xs-" + this.props.option : "card";
51         return <div className="container-fluid">
52              <div className="row">
53                 <div className="col-sm-4">
54                     <div className={option}>
55                         <div className="card-header">{content.header}</div>
56                         <img className="card-img-top" src={content.imgTop.url} alt={content.imgTop.alt}></img>
57                         {blocks}
58                         <ul className="list-group list-group-flush">
59                         {listGroup}
60                         </ul>
61                         <img className="card-img-bottom" src={content.imgBottom.url} alt={content.imgBottom.alt}></img>
62                         <div className="card-footer">{content.footer}</div>
63                     </div>
64                 </div>
65             </div>
66         </div>
67     }
68 })
69 
70 module.exports = Card

2.test.jsx

 1 var React = require('react/addons');
 2 var jasmineReact = require('jasmine-react-helpers');
 3 var TestUtils = React.addons.TestUtils;
 4 var Card = require('./Card.jsx');
 5 
 6 describe('Card component', function(){
 7 
 8     var card;
 9     var content;
10 
11     beforeEach(function(){
12         //渲染
13         var blocks = [
14             {
15                 title: "Allen Iverson",
16                 subtitle: "PG",
17                 text: "Cool player",
18                 links: [{
19                     url:"http://www.163.com",
20                     name:"链接1"
21                 }, {
22                     url:"http://www.g.cn",
23                     name:"链接2"
24                 }
25                 ]
26             }
27         ];
28         var header = "76ers";
29         var footer = "mvp";
30         var listGroup = ["艾弗森1996年6月26日被费城76人队选中,成为NBA状元秀,绰号答案(The Answer)","场均出战41.1分钟,获得26.7分、6.2次助攻和2.2次抢断"];
31         var imgTop = {
32             url: "http://a1.hoopchina.com.cn/attachment/Day_100424/43_3842044_665ae051136b4b8.jpg",
33             alt: "dribble"
34         };
35         var imgBottom = {
36             url: "http://www.onlinedown.net/bigsoftimg/androidimg/260000/255860_0.jpg",
37             alt: "crossover"
38         }
39         var content = {
40             blocks: blocks,
41             header: header,
42             footer: footer,
43             listGroup: listGroup,
44             imgBottom: imgBottom,
45             imgTop: imgTop
46         }
47         card = TestUtils.renderIntoDocument(<Card content={content} option="center"></Card>);
48     })
49 
50     afterEach(function(){
51         React.unmountComponentAtNode(React.findDOMNode(card))
52     })
53 
54     it('should exist', function(){
55         expect(!!React.findDOMNode(card)).toBe(true)
56         //card = TestUtils.renderIntoDocument(<Card content={content}></Card>);
57         //expect(React.findDOMNode(card).textContent).toContain('Hello world')
58     });
59 
60     it('should have correct structure', function(){
61         //测试
62         //card = TestUtils.renderIntoDocument(<Card content={content}></Card>);
63         var content = React.findDOMNode(card).textContent;
64         expect(content).toContain("Allen");
65         expect(content).toContain("76ers");
66         expect(content).toContain("mvp");
67         expect(content).toContain("艾弗森");
68         expect(React.findDOMNode(card).getElementsByTagName("img")[0].alt).toContain("dribble");
69         expect(React.findDOMNode(card).getElementsByTagName("img")[1].alt).toContain("crossover");
70 
71     });
72 
73     it('should have correct style', function() {
74         var cardBox = React.findDOMNode(card).getElementsByClassName("card");
75         expect(!!cardBox.length).toBe(true);
76     });
77 
78     it('should correctly use options', function() {
79         var cardBox = React.findDOMNode(card).getElementsByClassName("text-xs-center");
80         expect(!!cardBox.length).toBe(true);
81     });
82 
83     it('should be response', function() {
84         TestUtils.Simulate.click(React.findDOMNode(card).getElementsByTagName("a")[0]);
85         var content = React.findDOMNode(card).textContent;
86         expect(content).toContain("已关注");
87     });
88 })

3.show.jsx

 1 var React = require('react/addons');
 2 var Card = require('./Card.jsx');
 3 
 4 var blocks = [
 5     {
 6         title: "Allen Iverson",
 7         subtitle: "PG",
 8         text: "Cool player",
 9         links: [{
10             url:"http://www.163.com",
11             name:"链接1"
12         }, {
13             url:"http://www.g.cn",
14             name:"链接2"
15         }
16         ]
17     }
18 ];
19 var header = "76ers";
20 var footer = "mvp";
21 var listGroup = ["艾弗森1996年6月26日被费城76人队选中,成为NBA状元秀,绰号答案(The Answer)","场均出战41.1分钟,获得26.7分、6.2次助攻和2.2次抢断"];
22 var imgTop = {
23     url: "http://a1.hoopchina.com.cn/attachment/Day_100424/43_3842044_665ae051136b4b8.jpg",
24     alt: "dribble"
25 };
26 var imgBottom = {
27     url: "http://www.onlinedown.net/bigsoftimg/androidimg/260000/255860_0.jpg",
28     alt: "crossover"
29 }
30 var content = {
31     blocks: blocks,
32     header: header,
33     footer: footer,
34     listGroup: listGroup,
35     imgBottom: imgBottom,
36     imgTop: imgTop
37 }
38 React.render(<Card content={content} option="right"></Card>, document.body);

四、运行结果(bootstrap的css无效果)

源码:http://files.cnblogs.com/files/shamgod/BootstrapCard.zip

原文地址:https://www.cnblogs.com/shamgod/p/5079430.html