1、購物車列表功能實現
點擊加入購物車或者點擊購物車圖標后進入購物車頁面,在購物車頁面中首先渲染cartList的列表。首先加載init()方法,在init方法中發起get請求,請求cartList數據(不需要傳入參數)。在后端先解析出用戶cookie中的userId,查找文檔,如果找到了就把cartList返回去。
前端實現代碼
data(){
return{
cartList:[],
}
},
mounted(){
this.init();
},
methods:{
init(){
axios.get('/users/cartList').then((response)=>{
let res=response.data;
this.cartList=res.result;
})
}
},
components:{
NavHeader,
NavFooter,
NavBread,
Modal
}
}
后端實現代碼
//查詢當前用戶的購物車數據
router.get('/cartList',(req,res,next)=>{
let userId=req.cookies.userId;
User.findOne({userId:userId},(err,doc)=>{
if(err){
res.json({
status:'1',
msg:err.message,
result:''
})
}else{
res.json({
status:'0',
msg:'',
result:doc.cartList
})
}
})
})
2、商品刪除功能
點擊購物車頁面的刪除按鈕,彈出詢問是否刪除的模態框,并用變量productId記錄商品id,點擊模態框上的確認刪除后,向后端發起post請求,傳入參數商品id,后端返回響應后關閉模態框并重新調用init方法重新渲染購物車列表
前端代碼:
data(){
return{
cartList:[],
mdDel:false,
productId:''
}
},
mounted(){
this.init();
},
methods:{
init(){
axios.get('/users/cartList').then((response)=>{
let res=response.data;
this.cartList=res.result;
})
},
delPrd(id){
this.mdDel=true;
this.productId=id;
},
prdDel(){
axios.post('/users/delprd',{
productId:this.productId
}).then((response)=>{
let res=response.data;
if(res.status=='0'){
this.mdDel=false;
this.init();
}
})
}
},
components:{
NavHeader,
NavFooter,
NavBread,
Modal
}
}
后端代碼:
router.post('/delprd',(req,res,next)=>{
let userId=req.cookies.userId;
let pdId=req.body.productId;
User.update({userId:userId},{$pull:{'cartList':{'productId':pdId}}},(err,doc)=>{
if(err){
res.json({
status:'1',
msg:err.message,
result:''
})
}else{
res.json({
status:'0',
msg:'刪除成功',
result:'suc'
})
}
})
})
3、商品修改功能
點擊+-需要和前邊的是否選中需要修改商品數據。
首先加減是在+-的按鈕上調用editCart方法,并傳入商品item和+-的flag(add和minus)如果是+,就給item的productNum++,反之--。如果flag不是+-,就是check了,那此時將item的選中狀態變為相反數。全部改變完之后將數據傳到后端進行同步處理。通過axios的post請求,傳入參數商品id,商品數量,和商品的選中狀態。請求之后如果成功了就好,沒成功的話要把數量變回原值。并彈出提示信息。后端更新子文檔有不同的方法,可以先查找到子文檔在更新,也可以直接更新子文檔。后者比較簡單。
前端更新后的代碼:
data(){
return{
cartList:[],
mdDel:false,
productId:''
}
},
mounted(){
this.init();
},
methods:{
init(){
axios.get('/users/cartList').then((response)=>{
let res=response.data;
this.cartList=res.result;
})
},
delPrd(id){
this.mdDel=true;
this.productId=id;
},
prdDel(){
axios.post('/users/delprd',{
productId:this.productId
}).then((response)=>{
let res=response.data;
if(res.status=='0'){
this.mdDel=false;
this.init();
}
})
},
editCart(item,flag){
let oldNum=item.productNum;
if(flag=='add'){
item.productNum++;
}else if(flag=='minus'){
if(item.productNum<=1){
return;
}else{
item.productNum--;
}
}else{
item.checked*=-1;
}
axios.post('/users/changeNum',{
pdId:item.productId,
num:item.productNum,
checked:item.checked
}).then((response)=>{
let res=response.data;
if(res.status!='0'){
item.productNum=oldNum;
alert('更改商品數量失敗')
}
})
},
},
components:{
NavHeader,
NavFooter,
NavBread,
Modal
}
}
后端代碼:
router.post('/changeNum',(req,res,next)=>{
let userId=req.cookies.userId;
let pdId=req.body.pdId;
let num=req.body.num;
let checked=req.body.checked;
//先查找再更新
// User.findOne({userId:userId},(err,doc)=>{
// if(err){
// res.json({
// status:'1',
// msg:err.message,
// result:''
// })
// }else{
// doc.cartList.forEach((item)=>{
// if(item.productId==pdId){
// item.productNum=num;
// }
// });
// User.update({userId:userId},{
// $set: {cartList:doc.cartList}
// },(err)=>{
// if(err){
// res.json({
// status:'1',
// msg:err.message,
// result:''
// })
// }else{
// res.json({
// status:'0',
// msg:'',
// result:doc.cartList
// })
// }
// })
// }
// })
//直接更新子文檔
User.update({userId:userId,"cartList.productId":pdId},{
$set: {"cartList.$.productNum":num},
$set: {"cartList.$.checked":checked}
},(err)=>{//更新子文檔
if(err){
res.json({
status:'1',
msg:err.message,
result:''
})
}else{
res.json({
status:'0',
msg:'更新成功',
result:''
})
}
})
})
4、購物車全選
點擊全選按鈕時,將是否選中的狀態通過flag傳給后端,如果后端更新成功,前端就將遍歷商品將checked設置為相應狀態。在后端,首先接收是否需要全選isAll,然后通過userId找到用戶的cartLIst,遍歷列表,將整個cartList的checked設置為相應的狀態。改完之后保存數據
data(){
return{
cartList:[],
mdDel:false,
productId:''
}
},
mounted(){
this.init();
},
methods:{
init(){
axios.get('/users/cartList').then((response)=>{
let res=response.data;
this.cartList=res.result;
})
},
delPrd(id){
this.mdDel=true;
this.productId=id;
},
prdDel(){
axios.post('/users/delprd',{
productId:this.productId
}).then((response)=>{
let res=response.data;
if(res.status=='0'){
this.mdDel=false;
this.init();
}
})
},
editCart(item,flag){
let oldNum=item.productNum;
if(flag=='add'){
item.productNum++;
}else if(flag=='minus'){
if(item.productNum<=1){
return;
}else{
item.productNum--;
}
}else{
item.checked*=-1;
}
axios.post('/users/changeNum',{
pdId:item.productId,
num:item.productNum,
checked:item.checked
}).then((response)=>{
let res=response.data;
if(res.status!='0'){
item.productNum=oldNum;
alert('更改商品數量失敗')
}
})
},
selectAll(){
// this.isAll=!this.isAll;//在computed實時計算了不能在這再賦值了,
var flag=!this.isAll
axios.post('/users/selectAll',{
isAll:flag
}).then((response)=>{
if(response.data.status=='0'){
this.cartList.forEach((item)=>{
if(flag){
item.checked=1;
}else{
item.checked=-1;
}
})
}
})
},
},
components:{
NavHeader,
NavFooter,
NavBread,
Modal
}
}
后端代碼:
router.post('/selectAll',(req,res,next)=>{
let userId=req.cookies.userId;
let isAll=req.body.isAll;
User.findOne({userId:userId},(err,doc)=>{
if(err){
res.json({
status:'1',
msg:err.message,
result:''
})
}else{
doc.cartList.forEach((item)=>{
if(isAll){
item.checked=1;
}else{
item.checked=-1;
}
})
doc.save((err1,doc1)=>{
if(err1){
res.json({
status:'1',
msg:err.message,
result:''
})
}else{
res.json({
status:'0',
msg:'',
result:'suc'
})
}
})
}
})
})
5、商品實時計算功能
computed中添加的實際上是data,返回一個實時變化的值,這對計算商品總價錢很方便,首先將isAll變量用動態的商品屬性checked的個數來計算,如果checked的商品等于cartList里的商品長度,isAll就是全選的狀態,如果不是就不是全選的狀態。其次,總價錢也實時計算,遍歷整個列表,計算商品的個數*價錢。
computed:{//實時計算,相當于watch方法
isAll(){
let count=0;
this.cartList.forEach((item)=>{
if(item.checked==1){
count++;
}
})
return count===this.cartList.length;
},
totalMoney(){
let totalMoney=0;
this.cartList.forEach((item)=>{
if(item.checked==1){
totalMoney+=parseFloat(item.salePrice)*parseInt(item.productNum);
}
})
return totalMoney;
}
},
6、filter格式化
在組件內部定義filters,寫過濾方法,在頁面中需要格式化的地方調用
{{ totalMoney | currency('$')}}
import {currency} from './../util/currency'
filters:{
currency:currency
},
在main.js中定義全局過濾器。
import {currency} from './util/currency'
Vue.filter("currency",currency);
currency代碼:
const digitsRE = /(\d{3})(?=\d)/g
export function currency (value, currency, decimals) {
value = parseFloat(value)
if (!isFinite(value) || (!value && value !== 0)) return ''
currency = currency != null ? currency : '$'
decimals = decimals != null ? decimals : 2
var stringified = Math.abs(value).toFixed(decimals)
var _int = decimals
? stringified.slice(0, -1 - decimals)
: stringified
var i = _int.length % 3
var head = i > 0
? (_int.slice(0, i) + (_int.length > 3 ? ',' : ''))
: ''
var _float = decimals
? stringified.slice(-1 - decimals)
: ''
var sign = value < 0 ? '-' : ''
return sign + currency + head +
_int.slice(i).replace(digitsRE, '$1,') +
_float
}