03_01.利用node模块化开发项目01

1. 最终实现的效果

index.html
add.html

2. 逻辑思路分析图

逻辑分析

3. 模块分类

模块分类

4. 需要使用的第三方包插件

使用的第三方包

5. 模块分类

app.js(主要用来开启服务器)

//开启服务器
//核心 
var http = require("http");


//自定义
var render = require("./render.js");
var router = require("./router.js");

var server = http.createServer();

server.on("request",function(req,res){
    
    //在res中注册一个render方法
    render(res);

    //为下面代码的执行铺路:下面需要接收路径,根据不同的路径作出不同的处理,我们使用一个单独的模块来完成这个功能
    //这个模块我们取名叫做路由
    router(req,res);
});

server.listen(3000,function(){
    console.log("running");
});

render.js(主要是用来模板渲染)

var fs = require("fs");
var template = require("art-template");

//用来给res对象动态添加一个渲染方法
module.exports = function (res) {
    //作用:读取views下面的静态文件
    //参数一:url要读取的静态文件的名称  index.html  add.html
    //参数二:obj 要通过模板引擎渲染的数据
    //参数三:callback 给将来调用者设置一个回调函数,读取出数据以后怎么操作由调用者来决定
    //  现在callback中有两个参数:第一个参数是err,第二个参数是html
    //      由于我们将来对读取出来数据无非作这么几种处理:
    //          1)直接返回给浏览器,2)得到一个数据,将数据通过模板引擎进行渲染,渲染以后再返回给浏览器 
    res.render = function (url,obj,callback) {
        //将url转换为可以读取内容的路径
        var path = "./views/" + url;
        fs.readFile(path,function(err,data){
            if(err) {
                return callback(err);
            }
            //将数据进行渲染,并且响应到浏览器中
            var html = template.compile(data.toString())(obj || {});
            callback(null,html);
        });
    } 
}

router.js(主要是用来路由转发)

var handler = require("./handler.js");

//路由只是用来分发请求,得到请求的路径,并且判断路径,具体做什么事情,这个文件也不管
module.exports = function(req,res){
    //先拿到不同的请求
    var url = req.url;
    var method = req.method;
    //判断
    if(url == "/" && method == "GET") {
       handler.getIndex(req,res);
    } else if( url == "/add" && method == "GET") {
        handler.getAdd(req,res);
    } else if(url =="/upload" && method == "POST") {
        handler.postUpload(req,res);
    } else if( url == "/add" && method == "POST"){
       handler.postAdd(req,res);
    } else if (url.indexOf("/node_modules") == 0 || url.indexOf("/img") == 0) {
        handler.getStatic(req,res);
    }
}

handler.js(主要处理模块)

//负责处理具体的事物

var fs = require("fs");

//第三方
var formidable = require("formidable");

module.exports.getIndex = function(req,res){
    //封装读取静态文件的代码
    fs.readFile("./data.json",function(err,herosData){
        if(err) {
            return res.end("失败");
        }
        res.render("index.html",JSON.parse(herosData.toString()),function(err,html){
            if(err) {
                return res.end("失败");
            } 
            res.end(html);
        });
    });
}

module.exports.getAdd = function(req,res){
    res.render("add.html",null,function(err,data){
        if(err) {
            return res.end(err);
        } 
        res.end(data);
    });
}

module.exports.postAdd = function(req,res){
    res.writeHead(200,{
        "content-type": "text/html;charset=utf-8"
    });
    // 将原来通过data和end事件接收到的参数 改为通过第三方包formidable来接收
    //创建一个formidable对象
    var form = new formidable.IncomingForm();
    // //调用parse方法
    // //回调函数的三个参数:
    // //  参数一:err:错误信息
    // //  参数二:fields  字段  从浏览器端提交到服务器的一些属性
    // //  参数三:files   文件  从浏览器端上传过来的文件
    // //  由于formidable会将图片自动保存到一个临时目录下,而我们需要将图片保存到img下,所以需要设置一个图片的保存路径
    // form.uploadDir = "./img";
    // //  由于formidable默认不会保存文件的后缀名,所以我们需要将图片留后缀名
    // form.keepExtensions = true;
    form.parse(req, function(err, fields, files) {
        if(err) {
            return res.end("失败");
        }
        fs.readFile("./data.json",function(err,herosData){
            var heros = JSON.parse(herosData.toString());
            
            //根据得到的参数创建一个对象
            var obj = {};
            obj.name = fields.name;
            obj.gender = fields.gender;
            //得到heros中最后一条数据的id
            var id = heros.heros[heros.heros.length - 1].id + 1;
            obj.id = id;
            // obj.img = "/" + files.img.path;
            obj.img = fields.img;
            //将对象重新追倒hero中
            heros.heros.push(obj);
            //重新将对象写入到data.json中
            fs.writeFile("./data.json",JSON.stringify(heros,null,"  "),function(err){
                if(err) {
                    return res.end(retMsg(1,"失败"));
                }
                // res.end("<script>alert('新增成功');window.location='/'</script>");
                //返回的数据是交给浏览器中的异步对象的,而异步对象需要的一个json格式的字符串
                //将retobj对象作为返回给浏览器的数据,有这么几属性:
                //  statu: 表示的是当前操作的状态码:  0 成功  1 失败
                //  msg: 表示当前操作的 文本信息
                // var retObj = {
                //     statu: 0,
                //     msg: "操作成功"
                // };
                // res.end(JSON.stringify(retObj));
                res.end(retMsg());
            });
        });
        
    })
}


module.exports.postUpload = function(req,res){
    var form = new formidable.IncomingForm();
    form.uploadDir = "./img";
    form.keepExtensions = true;
    form.parse(req, function(err, fields, files) {
        if(err) {
            return res.end(retMsg(1,"失败"));
        }
        var imgName = "/" + files.img.path;
        res.end(retMsg(0,"成功",imgName));
    });
}

module.exports.getStatic = function(req,res) {
    var path = "." + req.url;
    fs.readFile(path,function(err,data){
        if(err) {
            return res.end("失败");
        }
        res.end(data);
    });
}

//设置一个统一的返回对象
//  statu:返回对象的状态  0成功 1失败
//  msg:返回对象信息
//  imgName: 返回对象的图片名称
function retMsg(statu,msg,imgName) {
    var obj = {};
    obj.statu = statu || 0;
    obj.msg = msg || "成功";
    obj.imgName = imgName || "";
    //将对象转为字符串返回
    return JSON.stringify(obj);
}

views下index.html以及add.html的内容
index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Hero - Admin</title>
  <link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.css">
  <style>
    .hero-list img {
      width: 50px;
    }
  </style>
</head>

<body>
  <header>
    <div class="page-header container">
      <h1>王者荣耀 <small>英雄管理器</small></h1>
    </div>
  </header>
  <div class="container hero-list">
    <a class="btn btn-success pull-right" href="/add">添加英雄</a>
    <table class="table table-hover">
      <thead>
        <th>编号</th>
        <th>名称</th>
        <th>性别</th>
        <th>头像</th>
        <th>操作</th>
      </thead>
      <tbody id="tbody"> 
        {{each heros}}
          <tr>
            <td>{{$value.id}}</td>
            <td>{{$value.name}}</td>
            <td>{{$value.gender}}</td>
            <td>![]({{$value.img}})</td>
            <td><a href="#">查看</a> <a href="#">修改</a> <a href="#">删除</a></td>
          </tr>
        {{/each}}
      </tbody>
    </table>
  </div>
</body>
</html>

add.html(异步传输用这个)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        table {
            margin: 0 auto;
            width: 500px;
            min-height: 300px;
        }
    </style>
</head>
<body>
    <form id="form" action="/add" method="POST" enctype="multipart/form-data">
        <table>
                <tr>
                    <td>姓名</td>
                    <td><input type="text" name="name" id="name"></td>
                </tr>
                <tr>
                    <td>性别</td>
                    <td><input id="man" type="radio" name="gender" value="男"><label for="man">男</label> <input type="radio"  name="gender" id="woman" value="女"><label for="woman">女</label></td>
                </tr>
                <tr>
                    <td>图片</td>
                    <td><img alt="" id="preImg"><input type="file" name="img" id="img"></td>
                </tr>
                <tr>
                    <td></td>
                    <td><input type="submit" id="btn" value="新增"></td>
                </tr>
            </table>
    </form>
</body>
<script src="/node_modules/jquery/dist/jquery.min.js"></script>
<script>
    //实现预览功能
    $("#img").on("change",function(){
        //1.0创建一个formData对象
        var fd = new FormData();
        //2.0提供参数:
        fd.append("img",document.getElementById("img").files[0]);

        //一旦选择了图片,我们需要将图片上传到服务器
        //为了不影响页面的正常运行,需要异步上传
        $.ajax({
            url: "/upload",
            type: "POST",
            data: fd,
            //告诉jquery不要验证我们fd中的参数的类型
            contentType: false,  
            //告诉jquery不要检查fd中提交的参数
            processData: false,  
            dataType: "JSON",
            success: function(result){
                if(result.statu == "0") {
                    //将返回的图片名称设置给img标签
                    $("#preImg").attr("src",result.imgName);
                } else {
                    alert(result.msg);
                    window.location = window.location;
                }
            }
        });
    });


    // 如果使用异步方式来提交新增的数据,jquery中的ajax方法会默认将提交数据的方式设置为
    // 与:enctype="application/x-www-form-urlencoded"      
    $("#btn").on("click",function(e){
        //在h5中为了能够更好的提交上传的参数,所以不能够使用form的serialize方法来序列化参数
        //可以用formdata来帮助我们上传参数
        //1.0创建一个formData对象
        var fd = new FormData();
        //2.0将要提交到服务器的参数添加到formData对象
        //append方法要传入两个参数:键值对象
        fd.append("name",$("#name").val());
        fd.append("gender",$("input[type=radio]:checked").val());
        // //document.getElementById("img").files[0]:得到上传过来的图片文件
        // fd.append("img",document.getElementById("img").files[0]);
        fd.append("img",$("#preImg").attr("src"));

        //阻止默认事件
        e.preventDefault();
        $.ajax({
            url: "add",
            type: "POST",
            // data: $("#form").serialize(),
            //关闭jquery内容的检查功能
            //告诉jquery不要验证我们fd中的参数的类型
            contentType: false,  
            //告诉jquery不要检查fd中提交的参数
            processData: false,  
            data: fd,
            dataType: "JSON",
            success: function(result){
                if(result.statu == 0) {
                    alert(result.msg);
                    window.location = "/";//跳转到/
                } else {
                    alert(result.msg);
                    window.location = window.location;//表示刷新当前页面
                }
            }
        });
    })
</script>
</html>

add.html(同步传输的话用这个)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        table {
            margin: 0 auto;
            width: 500px;
            height: 300px;
        }
    </style>
</head>
<body>
    <form action="/add" method="POST" enctype="multipart/form-data">
        <table>
                <tr>
                    <td>姓名</td>
                    <td><input type="text" name="name"></td>
                </tr>
                <tr>
                    <td>性别</td>
                    <td><input id="man" type="radio" name="gender" value="男"><label for="man">男</label> <input type="radio"  name="gender" id="woman" value="女"><label for="woman">女</label></td>
                </tr>
                <tr>
                    <td>图片</td>
                    <td><input type="file" name="img"></td>
                </tr>
                <tr>
                    <td></td>
                    <td><input type="submit" value="新增"></td>
                </tr>
            </table>
    </form>
</body>
</html>

data.json(模拟数据库存放的数据)

{
  "heros": [
    {
      "id": 1,
      "name": "亚瑟",
      "gender": "男",
      "img": "/img/1.jpg"
    },
    {
      "id": 2,
      "name": "李白",
      "gender": "男",
      "img": "/img/2.jpg"
    },
    {
      "id": 3,
      "name": "安奇拉",
      "gender": "女",
      "img": "/img/3.jpg"
    },
    {
      "id": 4,
      "name": "虞姬",
      "gender": "女",
      "img": "/img/4.jpg"
    }
  ]
}

开启node

图片.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,458评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,454评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,171评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,062评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,440评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,661评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,906评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,609评论 0 200
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,379评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,600评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,085评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,409评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,072评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,088评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,860评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,704评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,608评论 2 270

推荐阅读更多精彩内容