Vue node.js商城-购物车模块
一、渲染购物车列表页面
新建src/views/Cart.vue
获取cartList购物车列表数据就可以在页面中渲染出该用户的购物车列表数据
-
data(){
-
return {
-
cartList:[] // 购物车商品列表
-
}
-
},
-
mounted:function(){
-
this.init();
-
},
-
methods:{
-
init(){ // 初始化商品数据
-
axios.get('/users/cartList').then((response)=>{
-
let res = response.data;
-
this.cartList = res.result;
-
})
-
}
-
}
购物车接口:server/routes/users.js
-
// 查询当前用户的购物车数据
-
router.get('/cartList',function(req,res,next){
-
var userId = req.cookies.userId;
-
User.findOne({userId:userId},function(err,doc){
-
if(err){
-
res.json({
-
status:'1',
-
msg:err.message,
-
result:''
-
});
-
}else{
-
if(doc){
-
res.json({
-
status:'0',
-
msg:'',
-
result:doc.cartList
-
})
-
}
-
}
-
})
-
})
建立路由src/router/index.js
-
import Cart from '@/views/Cart' // 购物车列表
-
export default new Router({
-
routes: [
-
{
-
path: '/cart', // 购物车列表路由
-
name: 'Cart',
-
component: Cart
-
}
-
-
]
-
})
二、购物车商品删除功能
购物车删除接口:server/routes/users.js
-
// 购物车删除功能
-
router.post('/cartDel',function(req,res,next){
-
var userId = req.cookies.userId,productId = req.body.productId;
-
User.update({
-
userId:userId
-
},{
-
$pull:{
-
'cartList':{
-
'productId':productId
-
}
-
}
-
},function(err,doc){
-
if(err){
-
res.json({
-
status:'1',
-
msg:err.message,
-
result:''
-
});
-
}else{
-
res.json({
-
status:'0',
-
msg:'',
-
result:'suc'
-
});
-
}
-
})
-
});
src/views/Cart.vue
-
点击删除图标模态框出现(导入模态Modal.vue子组件)
-
<!-- 删除图标 -->
-
<a href="javascript:;" class="item-edit-btn" @click="delCartConfirm(item.productId)">
-
<svg class="icon icon-del">
-
<use xlink:href="#icon-del"></use>
-
</svg>
-
</a>
-
-
<!-- 模态框 -->
-
<Modal :mdShow="modalConfirm" @close="closeModal">
-
<p slot="message">你确认要删除此条数据吗?</p>
-
<div slot="btnGroup">
-
<a href="javascript:;" class="btn btn--m" @click="delCart">确认</a>
-
<a href="javascript:;" class="btn btn--m" @click="modalConfirm = false">关闭</a>
-
</div>
-
</Modal>
-
import Modal from '@/components/Modal.vue' // 模态框
-
export default {
-
data(){
-
return {
-
productId:'',
-
modalConfirm:false // 模态框是否显示
-
}
-
},
-
components:{
-
Modal
-
},
-
methods:{
-
delCartConfirm(productId){ // 点击删除图标
-
this.productId = productId;
-
this.modalConfirm = true; // 模态框显示
-
},
-
closeModal(){ // 关闭模态框
-
this.modalConfirm = false;
-
},
-
delCart(){ // 确认删除此商品
-
axios.post('/users/cartDel',{
-
productId:this.productId
-
}).then((response) => {
-
let res = response.data;
-
if(res.status = '0'){
-
this.modalConfirm = false; // 关闭模态框
-
this.init(); // 重新初始化购物车数据
-
}
-
})
-
}
-
}
-
}
**** 在这里发现一个bug,在商品列表页点击"加入购物车",购物车页面新添加的商品数量和总价格是未定义。mongoose添加属性问题
这是后端接口处理的问题,在server/routes/goods.js的加入到购物车接口中,是从mongodb的数据库dumall的goods表根据商品id获取对应数据,再对此商品数据添加productNum和checked属性,之后再插入到users表的购物车列表中的。
属性没有添加成功,在Goods模型中添加属性,要去models/goods.js的Schema添加这两个属性。
-
server/models/goods.js
-
// 定义一个Schema
-
var produtSchema = new Schema({
-
'productId':String,
-
'productName':String,
-
'salePrice':Number,
-
'productImage':String,
-
-
// 添加的属性
-
"checked":String,
-
"productNum":Number
-
})
-
module.exports = mongoose.model('good',produtSchema);
重新启动express(node server/bin/www)
三、购物车商品修改功能
商品加减和商品勾选
server/routes/users.js
-
//修改商品数量接口
-
router.post("/cartEdit",function(req,res,next){
-
var userId = req.cookies.userId,
-
productId = req.body.productId,
-
productNum = req.body.productNum,
-
checked = req.body.checked;
-
User.update({ // 查询条件
-
"userId":userId,
-
"cartList.productId":productId
-
},{ // 修改的数据
-
"cartList.$.productNum":productNum,
-
"cartList.$.checked":checked
-
},function(err,doc){
-
if(err){
-
res.json({
-
status:'1',
-
msg:err.message,
-
result:''
-
});
-
}else{
-
res.json({
-
status:'0',
-
msg:'',
-
result:'suc'
-
});
-
}
-
});
-
})
src/views/Cart.vue
-
<!--选中图标-->
-
<a href="javascipt:;" class="checkbox-btn item-check-btn" v-bind:class="{'check':item.checked=='1'}" @click="editCart('checked',item)">
-
<svg class="icon icon-ok">
-
<use xlink:href="#icon-ok"></use>
-
</svg>
-
</a>
-
<!--加减图标-->
-
<a class="input-sub" @click="editCart('minu',item)">-</a>
-
<a class="input-add" @click="editCart('add',item)">+</a>
-
-
methods:{
-
editCart(flag,item){
-
if(flag == 'add'){ // 添加商品数量
-
item.productNum++;
-
}else if(flag = 'minu'){ // 减少商品数量
-
if(item.productNum <= 1){
-
return;
-
}
-
item.productNum--;
-
}else{ // 商品控制选中
-
item.checked = (item.checked=='1') ? '0' : '1';
-
}
-
axios.post('/users/cartEdit',{
-
productId:item.productId,
-
productNum:item.productNum,
-
checked:item.checked
-
}).then((response)=>{
-
let res = response.data;
-
})
-
}
-
}
购物车全选和商品实时计算功能
- 全选和取消全选
server/routes/users.js
-
//全选和取消全选
-
router.post('/editCheckAll',function(req,res,next){
-
var userId = req.cookies.userId,
-
checkAll = req.body.checkAll?'1':'0';
-
User.findOne({userId:userId},function(err,user){
-
if(err){
-
res.json({
-
status:'1',
-
msg:err.message,
-
result:''
-
});
-
}else{
-
if(user){
-
user.cartList.forEach((item)=>{
-
item.checked = checkAll;
-
})
-
user.save(function (err1,doc) {
-
if(err1){
-
res.json({
-
status:'1',
-
msg:err1,message,
-
result:''
-
});
-
}else{
-
res.json({
-
status:'0',
-
msg:'',
-
result:'suc'
-
});
-
}
-
})
-
}
-
}
-
})
-
})
src/views/Cart.vue
-
<a href="javascipt:;" @click="toggleCheckAll">
-
<span class="checkbox-btn item-check-btn" v-bind:class="{'check':checkAllFlag}">
-
<svg class="icon icon-ok"><use xlink:href="#icon-ok"/></svg>
-
</span>
-
<span>Select all</span>
-
</a>
-
-
export default {
-
data(){
-
return {
-
checkAllFlag:false // 控制全选
-
}
-
},
-
methods:{
-
toggleCheckAll(){ // 全选和取消全选
-
this.checkAllFlag = !this.checkAllFlag; // 取反
-
this.cartList.forEach((item)=>{
-
item.checked = this.checkAllFlag;
-
})
-
axios.post('/users/editCheckAll',{
-
checkAll:this.checkAllFlag
-
}).then((response)=>{
-
let res = response.data;
-
if(res.status=='0'){
-
console.log("update suc");
-
}
-
})
-
}
-
}
-
}
这里出现一个问题,在点击select All全选之后,显示正常,但是刷新页面之后全选的图标没有显示全选,因为全选的信息没有存储到数据库保存,所以刷新之后就没有了。
【解决的办法】
用到了实时计算的computed功能,实时计算的是属性,只不过是函数的写法,data里面就不用在声明了。
src/views/Cart.vue
-
export default {
-
data(){
-
return {
-
// checkAllFlag:false // 控制全选
-
}
-
},
-
computed:{ // 实时计算的是属性,只不过是函数的写法,data里面就不用在声明了
-
checkAllFlag(){ // 是否全选属性
-
return this.checkedCount == this.cartList.length; // 勾选的商品种数=购物车商品列表的商品种数时,返回true代表全选。
-
},
-
checkedCount(){ // 获取已勾选的商品种数(几种商品已勾选)
-
var i = 0;
-
this.cartList.forEach((item)=>{
-
if(item.checked=='1')i++;
-
});
-
return i;
-
}
-
},
-
methods:{
-
toggleCheckAll(){ // 全选和取消全选
-
// this.checkAllFlag = !this.checkAllFlag;
-
// 不能使用这种写法了,checkAllFlag是实时计算的属性,如果true取反变成false之后,还没来得及执行下面的所有商品取消勾选,就实时计算了检测到勾选的商品种数=购物车商品列表的商品种数,就又变成全选了。
-
var flag = !this.checkAllFlag; // 声明变量取代
-
this.cartList.forEach((item)=>{
-
item.checked = flag ?'1':'0';
-
})
-
axios.post('/users/editCheckAll',{
-
checkAll:flag
-
}).then((response)=>{
-
let res = response.data;
-
if(res.status=='0'){
-
console.log("update suc");
-
}
-
})
-
}
-
}
-
}
页面一刷新就实时计算了
- 商品实时计算功能实现
这里也要用到computed计算属性
-
<div class="item-total">
-
Item total: <span class="total-price">{{totalPrice}}</span>
-
</div>
-
-
computed:{
-
totalPrice(){ // 总价格属性
-
var money = 0;
-
this.cartList.forEach((item)=>{
-
if(item.checked=='1'){
-
money += parseFloat(item.salePrice)*parseInt(item.productNum);
-
}
-
});
-
return money;
-
}
-
}
接下来要对价格进行格式化,vuex官网github有一个对购物车将格式化的函数https://github.com/vuejs/vuex/blob/dev/examples/shopping-cart/currency.js 可以拿过来对价格格式化,在src/util/currency.js
格式化要用到过滤器:可以在src/views/Cart.vue导入使用局部过滤器,也可以在main.js使用全局过滤器
-
<span class="total-price">{{totalPrice | currency('$')}}</span>
-
-
// 局部过滤器
-
import {currency} from '@/util/currency.js'
-
filters:{
-
currency:currency // currency.js传过来的本就是函数
-
},
-
-
// 全局过滤器
-
import {currency} from './util/currency'
-
Vue.filter("currency",currency);