• 前端用Webpact打包React后端Node+Express实现简单留言版


    前言

    React官方推荐用Browserify或者Webpack 来开发React组件。

    Webpack 是什么?是德国开发者 Tobias Koppers 开发的模块加载器。Instagram 工程师认为这个方案很棒, 似乎还把作者招过去了。在 Webpack 当中, 所有的资源都被当作是模块, js, css, 图片等等..Webpack 都有对应的模块 loader,如下文中将用到jsx-loader来加载带react语法的js文件

    Express 是目前最流行的 Node.js Web MVC开发框架,最受 Web 开发人员欢迎。使用其强大的功能,开发人员可以创建单页和多页,和混合模式的 Web 应用程序。本实例用Json数组模拟实现数据model模块,在Express框架下实现Restful API

    快速浏览更多在线 Demo

    想查看源代码,可以自行F12,或在github中直接查看源码,或者欢迎直接留言。

    [1]后端

    一、安装及配置环境[window环境]

    1、打开命令行,安装监听代码变更可自动重启node服务器的supervisor

    npm install -g supervisor

        在开发nodejs程序,调试的时候,无论你修改了代码的哪一部分,都需要重启服务才能生效。Node.js的这种设计虽然有利于提高性能,却不利于开发调试,因为我们在开发过程中总是希望修改后立即看到效果,而不是每次都要终止进程并重启。supervisor 可以帮助你实现这个功能,它会监视你对代码的改动,并自动重启 Node.js。

     

    2、命令行全局安装Nodejs MVC框架express。

    注意:如果运行有问题可以加上版本号安装。

    npm install -g express

    3、使用Express创建项目

    cd E:
    elson	estexpress    
    
    express -t ejs commentbox
    
    cd commentbox
    
    npm intall

          如上:命令行下先定位到自己的目录E: elson estexpress ,再输入express -t ejs commentbox创建项目,此时,会自动生成一个commentbox文件夹。文件夹里面面会有model、public、routes和views文件夹,还有app.js和package.json两个文件。再命令行cd commentbox定位到commentbox文件夹下,然后输入npm install(这是必需的),此时,目录下会多出node_modules文件夹,这是node模块文件夹。

     

    二、编写代码

    1、添加model文件E: elson estexpresscommentboxmodelcomments.js

    exports.comments = [
      { author : '小明', text : "Nothing is impossible, the word itself says 'I'm possible'!"},
      { author : '小强', text : "You may not realize it when it happens, but a kick in the teeth may be the best thing in the world for you"},
      { author : '小兵', text : "Even the greatest was once a beginner. Don't be afraid to take that first step."},
      { author : '拉登', text : "You are afraid to die, and you're afraid to live. What a way to exist."}
    ];

          用json数组模拟后台数据,当然可以直接去连数据库,写数据库连接配好model就可以了。

    2、修改应用入口文件E: elson estexpresscommentboxapp.js

    /**
     * Module dependencies.
     */
    
    var express = require('express');
    var routes = require('./routes');
    var comment = require('./routes/comment');
    var http = require('http');
    var path = require('path');
    
    var app = express();
    
    // all environments
    app.set('port', process.env.PORT || 3000);
    app.set('views', path.join(__dirname, 'views'));
    app.set('view engine', 'jade');
    //app.use(express.favicon());
    app.use(express.logger('dev'));
    app.use(express.json());
    app.use(express.urlencoded());
    app.use(express.methodOverride());
    app.use(express.bodyParser());
    app.use(app.router);
    app.use(express.static(path.join(__dirname, 'public')));
    
    // development only
    if ('development' == app.get('env')) {
      app.use(express.errorHandler());
    }
    
    app.get('/', routes.index);
    app.get('/comments', comment.list);
    app.get('/comments/:id', comment.get);  
    app.delete('/comments/:id', comment.delete);  
    app.post('/comments', comment.add);  
    app.put('/comments/:id', comment.update);  
    
    http.createServer(app).listen(app.get('port'), function(){
      console.log('Express server listening on port ' + app.get('port'));
    });

         红色部分是自己加上去的,定义好增删改查api接口。代码书写方式遵从CommonJS规范

     

    3、增加路由/控制器配置文件E: elson estexpresscommentbox outescomment.js

    /*
     * GET comments listing.
     */
    
    var comments = require('../model/comments').comments;  
      
    exports.list = function(req, res){  
      res.json(comments);  
    };  
      
    exports.get = function(req, res){  
       if(comments.length <= req.params.id || req.params.id < 0) {
        res.statusCode = 404;
        return res.send('Error 404: No comment found');
      }  
      var q = comments[req.params.id];
      res.json(q); 
    };  
      
      
    exports.delete = function(req, res){  
      if(comments.length <= req.params.id) {
        res.statusCode = 404;
        return res.send('Error 404: No comment found');
      }  
    
      comments.splice(req.params.id, 1);
      res.json(true); 
    };  
      
      
    exports.update = function(req, res){  
      res.setHeader('Content-Type', 'application/json;charset=utf-8'); 
      for(var i=0;i<comments.length;i++){
        if(comments[i].author==req.body.author){
          comments[i] = req.body;  
          res.send({status:"success", message:"update comment success"});  
          console.log(comments);        
        }
      } 
    
    };  
      
      
    exports.add = function(req, res){  
      if(!req.body.hasOwnProperty('author') || 
         !req.body.hasOwnProperty('text')) {
        res.statusCode = 400;
        return res.send('Error 400: Post syntax incorrect.');
      } 
     
      var newComment = {
        author : req.body.author,
        text : req.body.text
      }; 
     
      comments.push(newComment);
      res.json(true);   
    };

         这里比较清晰的定义了增删改查的请求处理

     

    4、命令行输入supervisor app.js,ok,现在打开浏览器输入localhost:3000你就可以运行并测试API接口了,也可以使用postman或者curl来测试,本例只用上了get与add请求。

    supervisor app.js

    浏览器打开http://localhost:3000/comments 

    结果如下:

    [
      {
        "author": "小明",
        "text": "Nothing is impossible, the word itself says 'I'm possible'!"
      },
      {
        "author": "小强",
        "text": "You may not realize it when it happens, but a kick in the teeth may be the best thing in the world for you"
      },
      {
        "author": "小兵",
        "text": "Even the greatest was once a beginner. Don't be afraid to take that first step."
      },
      {
        "author": "拉登",
        "text": "You are afraid to die, and you're afraid to live. What a way to exist."
      }
    ]

    浏览器打开http://localhost:3000/comments/1

    结果如下:

    {
      "author": "小强",
      "text": "You may not realize it when it happens, but a kick in the teeth may be the best thing in the world for you"
    }

    后端到此结束!

    [2]前端

    一、配置前端环境1、添加Webpack配置文件E: elson estexpresscommentboxwebpack.config.js

    module.exports = {
        entry: [
          './public/assets/js/entry.js'
        ],
        output: {
            path: __dirname + '/public/assets/',
            publicPath: "/public/assets/",
            filename: 'bundle.js'
        },
        module: {
            loaders: [
              { test: /.js?$/, loaders: ['jsx-loader?harmony'] }
            ]
        }
    };

         webpack.config.js是webpack默认的配置文件。如果改了文件名要重新执行:webpack --config webpack.config.js 这样的命令,如果不改文件名就直接输入webpack就会自动打包文件。

     

    2、命令行安装各种依赖模块。

    
    
    npm install -g webpack(如果没安装wepack的话需要全局安装
    npm install --save-dev jsx-loader
    npm install --save-dev react
    npm install --save-dev react-dom
    npm install --save-dev marked
    npm install --save-dev jquery

     

    二、编写前端js代码

    1、编写react 留言版组件:E: elson estexpresscommentboxpublicassetsjscommentbox.js

    var React = require('react');
    var ReactDOM = require('react-dom');
    var marked = require('marked');
    var $ = require('jquery');
    
    var Comment = React.createClass({
      rawMarkup: function() {
        var rawMarkup = marked(this.props.children.toString(), {sanitize: true});
        return { __html: rawMarkup };
      },
    
      render: function() {
        return (
          <div className="comment">
            <h2 className="commentAuthor">
              {this.props.author}
            </h2>
            <span dangerouslySetInnerHTML={this.rawMarkup()} />
          </div>
        );
      }
    });
    var CommentList = React.createClass({
      render: function() {
        var commentNodes = this.props.data.map(function (comment) {
          return (
            <Comment author={comment.author}>
              {comment.text}
            </Comment>
          );
        });     
        return (
          <div className="commentList">
            {commentNodes}
          </div>
        );
      }
    });
    
    var CommentForm = React.createClass({
      handleSubmit: function(e) {
        e.preventDefault();
        var author = this.refs.author.value.trim();
        var text = this.refs.text.value.trim();
        if (!text || !author) {
          return;
        }
        this.props.onCommentSubmit({author: author, text: text});
        this.refs.author.value = '';
        this.refs.text.value = '';
        return;
      },
      render: function() {
        return (
          <form className="commentForm" onSubmit={this.handleSubmit}>
            <input type="text" placeholder="你的名字" ref="author" />
            <input type="text" placeholder="说些什么..." ref="text" />
            <input type="submit" value="发表" />
          </form>
        );
      }
    });
    
    var CommentBox = React.createClass({
      loadCommentsFromServer: function() {
        $.ajax({
          url: this.props.url,
          dataType: 'json',
          cache: false,
          success: function(data) {
            this.setState({data: data});
          }.bind(this),
          error: function(xhr, status, err) {
            console.error(this.props.url, status, err.toString());
          }.bind(this)
        });
      },
      handleCommentSubmit: function(comment) {
        // TODO: submit to the server and refresh the list
        var comments = this.state.data;
        var newComments = comments.concat([comment]);
        this.setState({data: newComments});    
        $.ajax({
          url: this.props.url,
          dataType: 'json',
          type: 'POST',
          data: comment,
          success: function(data) {
            this.setState({data: data});
          }.bind(this),
          error: function(xhr, status, err) {
            console.error(this.props.url, status, err.toString());
          }.bind(this)
        });    
      },
      getInitialState: function() {
        return {data: []};
      },
      componentDidMount: function() {
        this.loadCommentsFromServer();
        setInterval(this.loadCommentsFromServer, this.props.pollInterval);
      },
      render: function() {
        return (
          <div className="commentBox">
            <h1>我的留言板</h1>
            <CommentList data={this.state.data} />
            <CommentForm onCommentSubmit={this.handleCommentSubmit} />
          </div>
        );
      }
    });
    
    module.exports = CommentBox; 

         这例子代码直接与react官方代码一样,只是改成了CommonJs风格。注意:webpack尊从CommonJS规范,使用起来非常方便,require相应的模块,如$ = require('jquery'),就可以直接使用jQuery,当然要先npm安装了要使用的模块。

     

    2、webpack入口js文件:E: elson estexpresscommentboxpublicassetsjsentry.js

    var React = require('react');
    var ReactDOM = require('react-dom');
    var CommentBox = require('./CommentBox');
    
    ReactDOM.render(
        <CommentBox url="/comments" pollInterval={2000} />,
        document.getElementById('commentbox')
     );

        可参考第1点配置文件里面定义好入口js文件,名称和路径要一致。

     

    3、添加留言版静态html页面:E: elson estexpresscommentboxpublichtmlindex.html

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>我的留言板</title>
    </head>
    <body>
        <div id="commentbox"></div>
        <script src="/assets/bundle.js"></script>
    </body>
    </html>

         bundle.js文件就是webpack打包好的js文件,引用进来就可以直接看到效果。

     

    4、命令行输入webpack打包js文件

    webpack

          这时,根据配置文件,在目录E: elson estexpresscommentboxpublicassets下会自动生成bundle.js文件

    5、好,大功告成;这时在刚才打开的浏览器页面修改url地址为:http://localhost:3000/html/index.html,效果如下:

     

    在页面上面测试发表留言,测试通过,OK

     

     

    前端React代码参考自官方教程,略有改动

    --React Tutorial https://facebook.github.io/react/docs/tutorial.html

    后端Restful API接口参考自

    --NODE.JS AND EXPRESS - CREATING A REST API http://blog.modulus.io/nodejs-and-express-create-rest-api

    --nodejs+Express实现Restful的web应用 http://blog.csdn.net/jthink_/article/details/9708087

  • 相关阅读:
    [hihoCoder] #1093 : 最短路径·三:SPFA算法
    [hihoCoder] #1089 : 最短路径·二:Floyd算法
    [LeetCode] Number of Islands
    PRML5-神经网络(1)
    CUDA2.4-原理之性能优化及浮点运算
    PRML1-引言
    PGM1.1-简介
    AI1.1-人工智能史
    数学-矩阵计算(4)两种布局
    数学-矩阵计算(2)矩阵函数微积分前奏
  • 原文地址:https://www.cnblogs.com/fastmover/p/4883162.html
Copyright © 2020-2023  润新知