web前端开发入门书 前端开发新建项目 入门前端开发用书
主要的功能介绍
- 用户可以完成注册、登录然后登录后对商品的浏览。
- 登录之后,用户可以对相关商品进行选购并添加到购物车。
- 用户可以对购物车里面的商品进行增加、减少、删除操作。
- 用户可对购物车商品进行结算操作。
使用的主要技术
1.NodeJS:node.js采用Google Chrome浏览器的V8引擎,一个后端的Javascript运行环境,提供很多系统级的API,如文件操作、网络编程等。
2.MongoDB:MongoDB是一个基于分布式文件存储的一个高性能,开源,无模式的文档型数据库,数据以BSON文档的格式存储在磁盘上。
3.Express:一个简洁、灵活的基于node.js的web应用开发框架, 支持Ejs、jade等多种模板,并且提供一系列强大的功能,比如:模板解析、静态文件服务、中间件、路由控制等等。
4.Mongoose:一个针对MongoDB操作的对象模型库,封装了MongoDB对文档的的一些增删改查等常用方法。
创建目录
- public目录:存放静态文件。
- routes目录:存放路由文件。
- views目录: 存放页面文件。
- common目录:存放公共文件。
安装项目所需的库 npm install
1.注册页面
首先在views下添加一个注册页面,register.html页面。
如何访问到注册页面呢?看如下代码app.js
javascript 代码
var express = require(‘express’)
var ejs = require(‘ejs’)
var path = require(‘path’)
var app = express()
app.set(‘view engine’, ‘
html’)
app.engine(‘.
html’, ejs.__express)
app.set(‘views’, path.join(__dirname, ‘views’))
app.use(express.static(path.join(__dirname, ‘public’)))
app.get(‘/’, function(req, res) {
res.render(‘register’)
})
app.listen(8000)
在浏览器上输入localhost:8000看看是否会跳入注册页面。
下面我们来看一下注册页面的逻辑处理的代码吧,
首先在common目录内添加models.js文件用来保存各个集合的Schema文件(集合属性),也便于我们查看和访问,具体内容如下所示:
**javascript 代码**
module.exports = {
user: {
name: { type: String, required: true },
password: { type: String, required: true },
gender: { type: Boolean, default: true },
},
}
还是common目录,我们在新建一个公共方法 —— dbHelper.js文件,来操作这些Schema,因为后面还会涉及此问题,所以我们写成一个公共的方法,dbHelper文件内容如下:
**javascript 代码**
var mongoose = require(‘mongoose’),
Schema = mongoose.Schema,
models = require(‘./models’)
for (var m in models) {
mongoose.model(m, new Schema(models[m]))
}
module.exports = {
getModel: function(type) {
return _getModel(type)
},
}
var _getModel = function(type) {
return mongoose.model(type)
}
关于dbHelper.js文件里方法的访问很简单,如下所示:global.dbHelper = require( './common/dbHelper' );
然后我们就开始修改register视图页面,添加单击事件,例如:<input type="button" onclick="register()" value="注 册" />
**javascript 代码**
function register() {
//通过serialize()方法进行序列化表单值,创建文本字符串。
var data = $(‘form’).serialize()
//例如:”username=张三&password=12345″
$.ajax({
url: ‘/register’,
type: ‘POST’,
data: data,
success: function(data, status) {
if (status == ‘success’) {
location.href = ‘register’
}
},
error: function(res, err) {
location.href = ‘register’
},
})
}
这里我们需要新建一个文件register.js,专门用来处理来之register页面的post请求, 在后面的学习中还会有多个不同处理文件,万所以我们统一管理在routes目录下,在实际开发中我们可能需要针对不同文件请求给出相应文件的处理,所以我们就做分开处理。
这里贴出register.js文件处理get和post请求的相关代码以供参考,如下:
**javascript 代码**
// app:express对象
module.exports = function(app) {
app.get(‘/register’, function(req, res) {
res.render(‘register’)
})
app.post(‘/register’, function(req, res) {
var User = global.dbHelper.getModel(‘user’),
uname = req.body.uname
User.findOne({ name: uname }, function(error, doc) {
if (doc) {
req.session.error = ‘用户名已存在!’
res.send(500)
} else {
User.create(
{
name: uname,
password: req.body.upwd,
},
function(error, doc) {
if (error) {
res.send(500)
} else {
req.session.error = ‘用户名创建成功!’
res.send(200)
}
},
)
}
})
})
}
register的post请求处理中,我们使用了session(express-session模块)还有处理post请求数据的body属性(body-parser和multer模块),需先安装他们,然后引用即可,如下参考:
**javascript 代码**
//引用模块
var bodyParser = require(‘body-parser’)
var multer = require(‘multer’)
var session = require(‘express-session’)
//调用中间件使用
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: true }))
app.use(multer())
后面我们还会再次添加多个路由记录,所以便于管理和访问,我们可以把他们统一放到一起,比如routes目录下新建index.js文件专门用来存放添加的文件,代码如下:
**javascript 代码**
module.exports = function(app) {
require(‘./register’)(app)
}
那么我们在app.js文件中直接引用index.js文件就可以访问这些文件了,如下所示:
**javascript 代码**
require(‘./routes’)(app); //app:express对象。;
这里我们就一步到位,在register的post请求处理中我们使用了express-session模块来保存相关信息,这里我们就使用中间件来传递这些提示信息,中间件内容如下所示:
**javascript 代码**
app.use(function(req, res, next) {
res.locals.user = req.session.user //保存用户信息
var err = req.session.error //保存结果响应信息
res.locals.message = ” // 保存
html标签
if (err)
res.locals.message =
‘<div class=”alert alert-danger” style=”margin-bottom: 20px;color:red;”>’ +
err +
‘</div>’
next()
})
这里注意中间件的安放位置,还有我们设置了变量message并为其简单添加了样式,这里我们在register视图里就用它来作为操作结果的信息提示,直接添加<%- message %>到视图第一个div内即可。
关于注册我们基本已经准备就绪,开始打开连接数据库并设置用户过期时间(注意执行顺序,应放置在首个中间件位置),app.js条件内容如下:
**javascript 代码**
mongoose.connect(‘mongodb://127.0.0.1:27017/test’)
app.use(
session({
secret: ‘secret’,
cookie: {
maxAge: 1000 * 60 * 30,
},
}),
)
登录页面
我们还是在views目录下添加登录视图页面 —— login.html;
这里我们还是添加一个相对应的文件用来处理login页面的请求,routes目录下新建名为login.js的文件,先来增加一个处理get请求的方法,代码参考如下:
javascript 代码
module.exports = function(app) {
app.get(‘/login’, function(req, res) {
res.render(‘login’)
})
}
和register文件一样添加到index.js中,如下:require(‘./login’)(app);
我们为登陆按钮增加单击事件和对应函数login(),参考如下:
javascript 代码
function login() {
//通过serialize()方法获取form表单内输入框用户名、密码的值
//如:”username=张三&password=12345″
var data = $(‘form’).serialize()
$.ajax({
url: ‘/login’,
type: ‘POST’,
data: data,
success: function(data, status) {
if (status == ‘success’) {
location.href = ‘home’
}
},
error: function(data, status) {
if (status == ‘error’) {
location.href = ‘login’
}
},
})
}
关于login视图页的post请求处理,我们需要判断用户所输入用户名是否存在,密码是否正确,并使用变量保存相应提示信息,当用户名和密码全部正确时,则返回成功并保存用户的个人信息,用作来判断用户的登陆状态,具体可参考register视图页的post请求。
login.js文件的post请求处理代码,参考如下:
**javascript 代码**
app.post(‘/login’, function (req, res) {
var User = global.dbHelper.getModel(‘user’),uname = req.body.uname;
User.findOne({name: uname}, function (error, doc) {
if (用户不存在) {
req.session.error = ‘用户名不存在!’;
res.send(404);
} else if(用户存在,密码错误) {
req.session.error = “密码错误!”;
res.send(404);
}else{ //用户名、密码正确
req.session.user=doc;
res.send(200);
}
});
});
}
home页面
用户登录成功之后则跳转至home视图页面(商品主页),就可以进行对商品的浏览和选择了。
还是views目录,添加home商品视图页;
用户成功登录之后跳转至home页,这里我们还是做分开处理,routes目录下新建home.js文件用来处理来之home也的get请求。
这里我们假设如果用户未登录将不能查看商品主页,所以,在请求处理中我们还需要判断用户的登陆状态,这个可以使用我们在登录处理时所保存的用户个人信息。
关于商品页的视图展示我们只需要有其名称、价格、图片,这里使用ejs模板循环展示,可参考如下方式:
html 代码
<html>
<head>
<title>主页</title>
<meta charset=”utf-8″>
<link href=”/bootstrap.min.
css” rel=”stylesheet” media=”screen”>
<script src=”/
jquery-2.1.1.min.js” type=”text/javascript”></script>
<script src=”/bootstrap.min.js” type=”text/javascript”></script>
.panel-title {
font-size: 24px;
font-weight: bold;
}
.spys {
list-style-type: none;
}
.spys li {
float: left;
margin: 10px 10px;
width: 180px;
height: 230px;
}
.spys li div strong {
color: red;
}
</style>
</head>
<body>
<div style=”margin:50px auto;width: 900px;”>
<div class=”panel panel-default”>
<div class=”panel-heading” style=”height: 40px;”>
<div style=”text-align: left”>
<span style=”font-size:20px; font-weight:bold;”>商品展示页</span>
<div style=”float: right;”>
<a class=”btn btn-xs btn-success” href=”addcommodity” style=”margin-right: 35px;”>添加商品</a>
<a class=”btn btn-xs btn-success” href=”cart” style=”margin-right: 35px;”>购物车</a>
<a class=”btn btn-xs btn-info” href=”logout”>退 出</a>
</div>
</div>
</div>
<div class=”panel-body”>
<ul class=”spys”>
<%for(var i in Commoditys){ if(!Commoditys[i].name)continue;%>
<li class=”spys li”>
<div>
<img width=”80″ height=”100″ src=”/img/<%=Commoditys[i].imgSrc%>”>
</div>
<div>
<a>
<%=Commoditys[i].name%></a>
<strong style=”color:red;”>¥
<%=Commoditys[i].price%></strong>
</div>
<div>
<a class=”btn btn-success” style=”width: 120px;” href=”/addToCart/<%=Commoditys[i]._id%>”>加入购物车</a>
</div>
</li>
<%}%>
</ul>
</div>
</div>
</div>
</body>
</html>
在home的get请求处理中,我们需要首先判断用户的登陆状态,只有用户登录了方可跳转到商品页,如果为登陆呢则跳转到登录页,而且在进入商品页的时候并传入Commodity集合的所有数据数据在页面展示。
routes目录下添加home.js文件(index.js文件中引用)。
**javascript 代码**
module.exports = function(app) {
app.get(‘/home’, function(req, res) {
if (req.session.user) {
var Commodity = global.dbHelper.getModel(‘commodity’)
Commodity.find({}, function(error, docs) {
//将Commoditys变量传入home模板
res.render(‘home’, { Commoditys: docs })
})
} else {
req.session.error = ‘请先登录’
res.redirect(‘/login’)
}
})
}
添加商品,views目录下添加addcommodity视图页面用来对商品的添加,这里简单样式参考如下:
相对应的addcommodity函数参考代码如下:
**javascript 代码**
//imgSrc表示图片路径),这里内置了5张图片,格式为:xmsz-X.jpg(X为1-5数字)。
var data =
$(‘form’).serialize() +
‘&imgSrc=’ +
‘xmsz-‘ +
Math.floor(Math.random() * 5 + 1) +
‘.jpg’
$.ajax({
url: ‘/addcommodity’,
type: ‘POST’,
data: data,
success: function(data, status) {
if (status == ‘success’) {
alert(‘添加成功!’)
}
},
error: function(data, err) {
alert(‘添加失败!’)
},
})
这里我们就直接在home.js文件中添加保存商品的处理方法;
javascript 代码
app.get(‘/addcommodity’, function(req, res) {
res.render(‘addcommodity’)
})
app.post(‘/addcommodity’, function(req, res) {
var Commodity = global.dbHelper.getModel(‘commodity’)
Commodity.create(
{
name: req.body.name,
price: req.body.price,
imgSrc: req.body.imgSrc,
},
function(error, doc) {
if (doc) {
res.send(200)
} else {
res.send(404)
}
},
)
})
结算页面
我们先定义购物车(cart)集合的Schema属性,包含:uId(用户ID)、cId(商品ID)、cName(商品名称)、cPrice(商品价格)、cImgSrc(商品展示图片路径)、cQuantity(商品数量)、cStatus(商品结算状态,默认为false),参考如下:
javascript 代码
cart:{
uId:{type:String},
cId:{type:String},
cName:{type:String},
cPrice:{type:String},
cImgSrc:{type:String},
cQuantity:{type:Number},
cStatus:{type:Boolean,default:false}
}
接着views目录下添加购物车(cart.html)视图页面,
代码如下:
html 代码
<!DOCTYPE html>
<html>
<head>
<title>购物车</title>
<meta charset=”utf-8″>
<link href=”/bootstrap.min.css” rel=”stylesheet” media=”screen”>
<script src=”/
jquery-2.1.1.min.js” type=”text/javascript”></script>
<script src=”/bootstrap.min.js” type=”text/javascript”></script>
<script type=”text/javascript”>
$(function () {
// 商品+-
$(‘.li-quantity a’).click(function () {
var self = $(this);
var type = self.attr(‘data-type’),
num = parseFloat(self.siblings(‘input’).val());
if (type == ‘add’) {
num += 1;
} else if (type == ‘subtr’) {
if (num > 1) {
num -= 1;
} else {
return false;
}
}
self.siblings(‘input’).val(num);
tamount();
});
//checkbox 单选事件
$(‘input[name=”chkItem”]:checkbox’).click(function () {
var isCheck = $(‘input[name=”chkItem”]:not(:checked)’).length ? false : true;
$(‘#CheckAll’).prop(“checked”, isCheck);
tamount();
});
//checkbox 全选事件
$(‘#CheckAll’).click(function () {
var self = $(this);
$(‘input[name=”chkItem”]’).each(function () {
$(this).prop(“checked”, self.is(‘:checked’));
});
tamount();
});
});
var sum = 0;
//用户结算
function Clearing() {
$(‘input[name=”chkItem”]:checked’).each(function () {
var self = $(this),
index = self.attr(‘data-index’),
cid = self.attr(‘data-id’);
var quantity = $(‘#Q’ + index).val();
var data = { “cid”: cid, “cnum”: quantity };
$.ajax({
url: ‘/cart/clearing’,
type: ‘post’,
data: data,
success: function (data, status) {
},
error: function (data, status) {
}
});
});
alert(‘¥’ + sum);
location.href = “cart”;
}
//计算商品总价格
function tamount() {
sum = 0;
$(‘input[name=”chkItem”]:checked’).each(function () {
var self = $(this),
price = self.attr(‘data-price’),
index = self.attr(‘data-index’);
var quantity = $(‘#Q’ + index).val();
sum += (parseFloat(price) * parseFloat(quantity));
});
$(“#money”).html(‘¥’ + sum + ‘.00’);
}
</script>
<style type=”text/css”>
.cart-heading {
height: 40px;
background-color: #EFEDED;
}
.cart-body {
background-color: #F7F7F7;
}
.cart-body ul li {
list-style-type: none;
margin-left: -30px;
width: 870px;
}
.cart-body ul li div {
float: left;
height: 80px;
}
.li-checkbox input {
margin: 20px 5px 0 0;
}
.li-img a img {
width: 40px;
height: 50px;
}
.li-content {
margin: 20px 0 0 30px;
width: 280px;
}
.li-price {
margin: 20px 0 0 60px;
width: 100px;
}
.li-quantity {
margin: 20px 0 0 130px;
width: 100px;
}
.li-del {
margin: 20px 0 0 30px;
width: 50px;
}
.li-img {
margin: 0 0 0 10px;
}
</style>
</head>
<body>
<div style=”margin:50px auto;width: 900px;”>
<div>
<div>
<div style=”float:right;”>
<a class=”btn btn-xs btn-success” href=”home” style=”margin-right: 35px;”>商品页</a>
<a class=”btn btn-xs btn-info” href=”logout”>退 出</a>
</div>
<h2>购物车</h2>
<hr>
</div>
<div>
<div class=”cart-heading”>
<div style=”padding: 10px 0 0 10px”>
<span style=”margin-right: 200px;”>
<input id=”CheckAll” type=”checkbox”> 全选
</span>
<span style=”margin-right: 180px;”>商品</span>
<span style=”margin-right: 210px;”>价格</span>
<span style=”margin-right: 80px;”>数量</span>
<span style=”padding-right: 0px;”>操作</span>
</div>
</div>
<div class=”cart-body”>
<ul>
<%for(var i in carts){ if(!carts[i].cId)continue%>
<li>
<div class=”li-checkbox”>
<input data-id=”<%=carts[i]._id%>” data-index=”<%=i%>” data-price=”<%=carts[i].cPrice%>” name=”chkItem” class=”li-checkbox input”
type=”checkbox” />
</div>
<div class=”li-img”>
<a>
<img class=”li-img a img” src=”/img/<%=carts[i].cImgSrc%>”>
</a>
</div>
<div class=”li-content”>
<a>
<%=carts[i].cName%></a>
</div>
<div class=”li-price”>
<span>
<%=carts[i].cPrice%></span>
</div>
<div class=”li-quantity”>
<a data-type=”add” href=”javascript:void(0);” class=”btn btn-default btn-xs “>+</a>
<input id=”Q<%=i%>” style=”width: 40px;” type=”text” value=”<%=carts[i].cQuantity%>”>
<a data-type=’subtr’ href=”javascript:void(0);” class=”btn btn-default btn-xs”>-</a>
</div>
<div class=”li-del”>
<a href=”/delFromCart/<%=carts[i]._id%>” class=”btn btn-primary btn-xs”>删除</a>
</div>
</li>
<%}%>
</ul>
</div>
<div style=”float: right;height: 35px;width:330px;”>
总计:<span id=”money” style=”color: red;font-size: 25px”>¥0.00</span>
<input type=”button” style=”width: 130px;float:right;” class=”btn btn-success” onclick=” Clearing();” value=”结 算” />
</div>
</div>
</div>
</div>
</body>
</html>
javascript 代码
module.exports = function(app) {
//查看购物车商品
app.get(‘/cart’, function(req, res) {
var Cart = global.dbHelper.getModel(‘cart’)
if (!req.session.user) {
req.session.error = ‘用户已过期,请重新登录:’
res.redirect(‘/login’)
} else {
Cart.find({ uId: req.session.user._id, cStatus: false }, function(
error,
docs,
) {
res.render(‘cart’, { carts: docs })
})
}
})
//添加购物车商品
app.get(‘/addToCart/:id’, function(req, res) {
//req.params.id 获取商品ID号
if (!req.session.user) {
req.session.error = ‘用户已过期,请重新登录:’
res.redirect(‘/login’)
} else {
var Commodity = global.dbHelper.getModel(‘commodity’),
Cart = global.dbHelper.getModel(‘cart’)
Cart.findOne({ uId: req.session.user._id, cId: req.params.id }, function(
error,
doc,
) {
//商品已存在 +1
if (doc) {
Cart.update(
{ uId: req.session.user._id, cId: req.params.id },
{ $set: { cQuantity: doc.cQuantity + 1 } },
function(error, doc) {
//成功返回1 失败返回0
if (doc > 0) {
res.redirect(‘/home’)
}
},
)
//商品未存在,添加
} else {
Commodity.findOne({ _id: req.params.id }, function(error, doc) {
if (doc) {
Cart.create(
{
uId: req.session.user._id,
cId: req.params.id,
cName: doc.name,
cPrice: doc.price,
cImgSrc: doc.imgSrc,
cQuantity: 1,
},
function(error, doc) {
if (doc) {
res.redirect(‘/home’)
}
},
)
} else {
}
})
}
})
}
})
//删除购物车商品
app.get(‘/delFromCart/:id’, function(req, res) {
//req.params.id 获取商品ID号
var Cart = global.dbHelper.getModel(‘cart’)
Cart.remove({ _id: req.params.id }, function(error, doc) {
//成功返回1 失败返回0
if (doc > 0) {
res.redirect(‘/cart’)
}
})
})
//购物车结算
app.post(‘/cart/clearing’, function(req, res) {
var Cart = global.dbHelper.getModel(‘cart’)
Cart.update(
{ _id: req.body.cid },
{ $set: { cQuantity: req.body.cnum, cStatus: true } },
function(error, doc) {
//更新成功返回1 失败返回0
if (doc > 0) {
res.send(200)
}
},
)
})
}
前端开发做项目的经历 前端开发从入门到精通 前端项目开发流程
评论前必须登录!
注册