React問答小demo

在學習react初期,看了一些視頻和資料,react基礎知識差很少學完,跟着網上的一個教程,作了一個小型的問答demo。css

需求看圖說:html

1.點擊「添加」按鈕,顯示問題輸入表單,再次點擊,隱藏表單。同時,點擊「取消」按鈕,隱藏表單。react

2.輸入問題標題和內容後,點擊「確認」按鈕,將問題顯示在下方(按照投票數從高到低)。git

3.每一個問題有加票和減票功能,在點擊的同時,將問題按照投票數從高到低排序。程序員

實現過程:github

1、開發環境和工具npm

1.npm init (生成package.json文件) (按照嚮導填寫各個字段,最後生成 package.json 文件。編程

容易出錯的是: name的值不要和包包同名 。json

好比咱們後續須要使用npm安裝幾個包包:browserify react reactify ...則name值若是寫做「browserify」或「react」,此依賴會安裝失敗!redux

提示以下:

npm WARN install Refusing to install react as a dependency of itself)

2.npm install react --save        npm install react-dom --save (最開始就是沒有安裝react-dom,因此一直渲染不出來)

3.npm install -g gulp

4.npm install --save-dev gulp gulp-browserify gulp-concat gulp-react gulp-connect lodash reactify

(這裏注意一下,npm install --save 與 npm install --save-dev 的區別,一個放在package.json 的dependencies , 一個放在devDependencies裏面,產品模式用dependencies,開發模式用devDep。)

5.bower init (生成bower.json文件)

6.bower install bootstrap --save

7.新建app文件夾,再在下面建一個js文件夾,建立main.js

8.新建dist文件(壓縮後的文件放的地方)

9.建立gulpfile.js

2、代碼開發

gulpfile.js內容以下:

 1 var gulp = require('gulp'),
 2     connect = require('gulp-connect'),
 3     browserify = require('gulp-browserify'),
 4     concat = require('gulp-concat'),
 5     port = process.env.port || 5000;
 6 
 7 gulp.task('browserify',function(){
 8     gulp.src('./app/js/main.js')
 9         .pipe(browserify({
10             transform: 'reactify',
11         }))
12         .pipe(gulp.dest('./dist/js'))
13 });
14 
15 // live reload
16 gulp.task('connect',function(){
17     connect.server({
18         // root:'./',
19         port: port,
20         livereload: true
21     })
22 })
23 
24 // reload Js
25 gulp.task('js',function(){
26     gulp.src('./dist/**/*.js')
27         .pipe( connect.reload() )
28 })
29 
30 gulp.task('html',function(){
31     gulp.src('./app/**/*.html')
32         .pipe( connect.reload() )
33 });
34 
35 gulp.task('watch',function(){
36     gulp.watch('./dist/**/*.js',['js']);
37     gulp.watch('./app/**/*.html',['html']);
38     gulp.watch('./app/js/**/*.js',['browserify']);
39 })
40 
41 gulp.task('default',['browserify']);
42 
43 gulp.task('serve',['browserify','connect','watch']);

靜態頁面html:

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4     <meta charset="utf8">
 5     <title>React問答 app </title>
 6     <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css">
 7     <style>
 8         .container{
 9             max-width: 800px;
10         }
11         .jumbotron .container{
12             position: relative;
13             max-width: 800px;
14         }
15         #add-question-btn{
16             position: absolute;
17             bottom: -20px;
18             right: 20px;
19         }
20         form[name="addQuestion"] .btn{
21             margin: 20px 0 0 15px;
22         }
23         .media-left{
24             text-align: center;
25             width:70px;
26             float: left;
27         }
28         .media-left .btn{
29             margin-bottom: 10px;
30         }
31         .vote-count{
32             display: block;
33         }
34     </style>
35 </head>
36 <body>
37 <div id="app">
38     <div class="jumbotron text-center">
39         <div class="container">
40             <h1>React問答</h1>
41             <button id="add-question-btn" class="btn btn-success">添加問題</button>
42         </div>
43     </div>
44     <div class="main container">
45         <form name="addQuestion" class="clearfix">
46             <div class="form-group">
47                 <label for="qtitle">問題</label>
48                 <input type="text" class="form-control" id="qtitle" placeholder="您的問題的標題">
49             </div>
50             <textarea class="form-control" rows="3" placeholder="問題的描述"></textarea>
51             <button class="btn btn-success pull-right">確認</button>
52             <button class="btn btn-default pull-right">取消</button>
53         </form>
54         <div id="questions" class="">
55             <div class="media">
56                 <div class="media-left">
57                     <button class="btn btn-default">
58                         <span class="glyphicon glyphicon-chevron-up"></span>
59                         <span class="vote-count">22</span>
60                     </button>
61                     <button class="btn btn-default">
62                         <span class="glyphicon glyphicon-chevron-down"></span>
63                     </button>
64                 </div>
65                 <div class="media-body">
66                     <h4 class="media-heading">產品經理與程序員矛盾的本質是什麼?</h4>
67                     <p>理性探討,請勿撕逼。產品經理的主要工做職責是產品設計。接受來自其餘部門的需求,通過設計後交付研發。但這裏有好些職責不清楚的地方。</p>
68                 </div>
69             </div>
70 
71             <div class="media">
72                 <div class="media-left">
73                     <button class="btn btn-default">
74                         <span class="glyphicon glyphicon-chevron-up"></span>
75                         <span class="vote-count">12</span>
76                     </button>
77                     <button class="btn btn-default">
78                         <span class="glyphicon glyphicon-chevron-down"></span>
79                     </button>
80                 </div>
81                 <div class="media-body">
82                     <h4 class="media-heading">熱愛編程是一種怎樣的體驗?</h4>
83                     <p>別人對玩遊戲感興趣,我對寫代碼、看技術文章感興趣;把泡github、stackoverflow、v2ex、reddit、csdn當作是興趣愛好;遇到重複的工做,總想着能不能經過程序實現自動化;喝酒的時候把寫代碼當下酒菜,邊喝邊想邊敲;不給工資我也會來加班;作夢都在寫代碼。</p>
84                 </div>
85             </div>
86 
87         </div>
88 
89     </div>
90 </div>
91 
92 <!--
93 <script src="/dist/js/main.js"></script>  -->
94 </body>
95 </html>

接下來的react代碼轉化,我就不詳細謝了,在這裏貼出個人項目文件展現:

index.html

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4     <meta charset="utf8">
 5     <title>React問答 app </title>
 6     <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css">
 7     <style>
 8         .container{
 9             max-width: 800px;
10         }
11         .jumbotron .container{
12             position: relative;
13             max-width: 800px;
14         }
15         #add-question-btn{
16             position: absolute;
17             bottom: -20px;
18             right: 20px;
19         }
20         form[name="addQuestion"] .btn{
21             margin: 20px 0 0 15px;
22         }
23         .media-left{
24             text-align: center;
25             width:70px;
26             float: left;
27         }
28         .media-left .btn{
29             margin-bottom: 10px;
30         }
31         .vote-count{
32             display: block;
33         }
34     </style>
35 </head>
36 <body>
37 <div id="app"> </div>
38 
39 <script src="/dist/js/main.js"></script>
40 
41 </body>
42 </html>

main.js

1 var React = require('react');
2 var ReactDOM = require('react-dom');
3 var QuestionApp = require('./components/QuestionApp.js');
4 /* 模塊名可以使用相對路徑(以./開頭),或者是絕對路徑(以/或C:之類的盤符開頭)*/
5 
6 var mainCom = ReactDOM.render(
7     <QuestionApp />,
8     document.getElementById('app')
9 );

QuestionApp.js

 1 var React = require('react');
 2 var ShowAddBtn = require('./ShowAddBtn.js');
 3 var QuestionForm = require('./QuestionForm.js');
 4 var QuestionList = require('./QuestionList.js');
 5 module.exports = React.createClass({
 6     getInitialState: function(){
 7         var questions = [
 8             {
 9                 key: 1,
10                 title: '產品經理與程序員矛盾的本質是什麼?',
11                 description: '理性探討,請勿撕逼。產品經理的主要工做職責是產品設計。接受來自其餘部門的需求,通過設計後交付研發。但這裏有好些職責不清楚的地方。',
12                 voteCount: 2
13             },
14             {
15                 key: 2,
16                 title: '熱愛編程是一種怎樣的體驗?',
17                 description: '別人對玩遊戲感興趣,我對寫代碼、看技術文章感興趣;把泡github、stackoverflow、v2ex、reddit、csdn當作是興趣愛好;遇到重複的工做,總想着能不能經過程序實現自動化;喝酒的時候把寫代碼當下酒菜,邊喝邊想邊敲;不給工資我也會來加班;作夢都在寫代碼。',
18                 voteCount: 3
19             }
20         ];
21         questions = this.questionSort(questions); //sort the init questions
22         return {
23             displayForm: false,
24             questions: questions
25         };
26     },
27     onToggleForm: function(){
28         this.setState({
29             displayForm: !this.state.displayForm
30         });
31     },
32     onQuestionNew: function(newQuestion){
33         newQuestion.key = this.state.questions.length + 1;
34         var newQuestions = this.state.questions.concat(newQuestion);
35         newQuestions = this.questionSort(newQuestions);
36         this.setState({
37             questions: newQuestions
38         });
39     },
40     questionSort: function(questions){
41         questions.sort(function(a,b){
42             return b.voteCount - a.voteCount;
43         });
44         return questions;//以前一直報錯,這裏忘記return
45     },
46     onVote: function(nowKey, newVoteCount){
47         var questions = this.state.questions;
48         var index = 0;
49         for(var i=0; i<questions.length; i++){
50             if(questions[i].key == nowKey){
51                 index = i;
52             }
53         }
54         questions[index].voteCount = newVoteCount;
55         questions = this.questionSort(questions);
56         this.setState({
57             questions: questions
58         });
59     },
60     render: function(){
61         return (
62             <div>
63                 <div className="jumbotron text-center">
64                     <div className="container">
65                         <h1>React問答</h1>
66                         <ShowAddBtn onToggleForm={this.onToggleForm}/>
67                     </div>
68                 </div>
69                 <div className="main container">
70                     <QuestionForm onQuestionNew={this.onQuestionNew} displayForm={this.state.displayForm} onToggleForm={this.onToggleForm}/>
71                     <QuestionList onVote={this.onVote} questions={this.state.questions}/>
72                 </div>
73             </div>
74         )
75     }
76 });

ShowAddBtn.js

1 var React = require('react');
2 module.exports = React.createClass({
3     render: function(){
4         return (
5             <button id="add-question-btn" className="btn btn-success" onClick={this.props.onToggleForm}>添加問題</button>
6         )
7     }
8 });

QuestionForm.js

 1 var React = require('react');
 2 module.exports = React.createClass({
 3     handleSubmit: function(e){
 4         e.preventDefault();
 5         var newQuestion = {
 6             title: this.refs.title.value,
 7             description: this.refs.description.value,
 8             voteCount: 0
 9         };
10         this.refs.questionForm.reset();
11         this.props.onQuestionNew(newQuestion);
12     },
13     render: function(){
14         return (
15             <form name="addQuestion" className="clearfix" ref="questionForm"
16                   style={{display: this.props.displayForm ? 'block' : 'none'}}
17                   onSubmit={this.handleSubmit}>
18                 <div className="form-group">
19                     <label htmlFor="qtitle">問題</label>
20                     <input ref="title" type="text" className="form-control" id="qtitle" placeholder="您的問題的標題"/>
21                 </div>
22                 <textarea ref="description" className="form-control" rows="3" placeholder="問題的描述"></textarea>
23                 <button className="btn btn-success pull-right">確認</button>
24                 <a className="btn btn-default pull-right" onClick={this.props.onToggleForm}>取消</a>
25             </form>
26         )
27     }
28 });

QuestionList.js

 1 var React = require('react');
 2 var QuestionItem = require('./QuestionItem.js');
 3 module.exports = React.createClass({
 4     render: function(){
 5         var questions = this.props.questions;
 6         var _this = this;//這裏的this要單獨保存,不然下面的map中的this指的是循環的每一個對象
 7         var questionComps = questions.map(function(qst){
 8             return <QuestionItem
 9                 key={qst.key}
10                 questionKey={qst.key}
11                 title={qst.title}
12                 description={qst.description}
13                 voteCount={qst.voteCount}
14                 onVote={_this.props.onVote}/>
15         });
16         //開始一直報錯,是由於這裏,render裏面,return(), 沒有寫最外層div
17         return (
18             <div id="questions" className="">
19                 {questionComps}/*直接放個數組在這裏,他會自動去循環*/
20             </div>
21         )
22     }
23 });

QuestionItem.js

 1 var React = require('react');
 2 module.exports = React.createClass({
 3     voteUp: function(){
 4         var newVoteCount = parseInt(this.props.voteCount, 10) + 1;
 5         //this.props.questionKey這裏必須重
 6         // 新定義一個questionKey屬性, 不能this.props.key
 7         this.props.onVote(this.props.questionKey, newVoteCount);
 8     },
 9     voteDown: function(){
10         var newVoteCount = parseInt(this.props.voteCount, 10) - 1;
11         this.props.onVote(this.props.questionKey, newVoteCount);
12     },
13     render: function(){
14         return (
15             <div className="media">
16                 <div className="media-left">
17                     <button className="btn btn-default" onClick={this.voteUp}>
18                         <span className="glyphicon glyphicon-chevron-up"></span>
19                         <span className="vote-count">{this.props.voteCount}</span>
20                     </button>
21                     <button className="btn btn-default" onClick={this.voteDown}>
22                         <span className="glyphicon glyphicon-chevron-down"></span>
23                     </button>
24                 </div>
25                 <div className="media-body">
26                     <h4 className="media-heading">{this.props.title}</h4>
27                     <p>{this.props.description}</p>
28                 </div>
29             </div>
30         )
31     }
32 
33 });

到這裏,全部代碼就完成了,在命令行裏面執行gulp serve命令,而後在瀏覽器中訪問localhost:5000。

 

到此整個小demo就算完成了。對於react-router, react redux等深刻知識點還在進一步學習過程當中,歡迎你們提出問題,一塊兒討論。

相關文章
相關標籤/搜索