1. 最终实现的效果
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