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无效果)
源码:https://files.cnblogs.com/files/shamgod/BootstrapCard.zip
You can do anything you set your mind to, man!