加入購物車功能實現
在models中建一個使用者模型user,使用者模型需要關聯
引入mongoose
var mongoose = require('mongoose');
拿到mongoose以後,需要建立Schema模型,模型的欄位必須與資料庫對應起來。
var userSchema = mongoose.Schema({
"userId":String, // 使用者Id
"userName":String, // 使用者名稱
"userPwd":String, // 使用者密碼
"orderList":Array, // 訂單列表
"cartList":[ // 購物車列表
{
"productId": String, // 商品Id
"productName": String, // 商品名稱
"salePrice":String, // 商品價格
"productImage":String, // 圖片地址
"checked":String, // 是否選中
"productNum":String // 商品數量
}
],
"addressList":Array // 使用者地址列表
});
通過module.exports進行輸出,這樣才能載入到 三個引數分別是 模型名,userSchema名,管理資料庫集合名
module.exports = mongoose.model("User",userSchema,"users");
在商品模型models/goods.js中新增商品數量prodcutNum和是否選擇屬性checked
var produtSchema = new Schema({
"productId":String,
"productName":String,
"salePrice":Number,
"prodcutNum": Number,
"checked":String,
"prodcutImage": String
});
》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
購物車業務邏輯
第一步:拿到使用者資訊,判斷使用者是否存在
第二步:如果使用者資訊中存在此商品,則新增商品數量
第三步:如果使用者資訊中不存在此商品,則新增此商品,並設定為選擇狀態
node後端程式碼
models/user.js 使用者模型
var mongoose = require('mongoose')
var userSchema = mongoose.Schema({
"userId":String, // 使用者Id
"userName":String, // 使用者名稱
"userPwd":String, // 使用者密碼
"orderList":Array, // 訂單列表
"cartList":[ // 購物車列表
{
"productId": String, // 商品Id
"productName": String, // 商品名稱
"salePrice":String, // 商品價格
"productImage":String, // 圖片地址
"checked":String, // 是否選中
"productNum":String // 商品數量
}
],
"addressList":Array // 使用者地址列表
});
// 通過module.exports進行輸出,這樣才能載入到 三個引數分別是 模型名,userSchema名,管理資料庫集合名
module.exports = mongoose.model("User",userSchema,"users");
node查詢商品列表及新增購物車邏輯
routes/goods.js
var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
var Goods = require('../models/goods');
// 連線MongoDB資料庫
mongoose.connect('mongodb://47.100.191.231:27017/dumall');
// 通過mongoose.connect.on的形式去監聽資料庫有沒有連線成功
mongoose.connection.on("connected",function () {
console.log("MongoDB connected success.")
})
// 連線失敗
mongoose.connection.on("error",function () {
console.log("MongoDB connected fail.")
})
// 連線斷開
mongoose.connection.on("disconnected",function () {
console.log("MongoDB connected disconnected.")
})
// next是往後繼續執行的物件
// 查詢商品列表資料
router.get("/", function (req,res,next) {
let page = parseInt(req.param("page")); // 獲取分頁引數 第幾頁
let pageSize = parseInt(req.param("pageSize")); // 獲取一頁多少條資料 必須要是數字
let priceLevel = req.param("priceLevel"); // 接收篩選價格
let sort = req.param("sort"); // 獲取排序引數
let skip = (page-1)*pageSize; // 分頁計算公式
var priceGt = '',priceLte = ''; // 篩選價格的區間
let = params = {};
// 當priceLevel不等於all是執行,預設是all
if(priceLevel!='all'){
switch (priceLevel){
case '0':
priceGt = 0; priceLte=100;
break;
case '1':
priceGt = 100; priceLte=500;
break;
case '2':
priceGt = 500; priceLte=1000;
break;
case '3':
priceGt = 1000; priceLte=5000;
break;
}
params = {
salePrice:{
$gt:priceGt, // 篩選價格大於priceGt
$lte:priceLte // 篩選價格小於priceLte
}
}
}
// 通過skip param 和limit來實現分頁, skip表示跳過幾條資料 limit表示一頁多少條資料
let goodsModel = Goods.find(params).skip(skip).limit(pageSize);
// 宣告對哪個欄位進行排序 ,這裡如salePrice金額 sort 1 為升序,-1 為降序
goodsModel.sort({'salePrice':sort});
// 第一個是引數,目前沒有入參
// 返回的是兩個引數,第一個是報錯err,第二個是文件
// 因為這裡不是普通的查詢,經過到這裡已經執行了很多步驟了 下面通過exec來執行我們的方法
// exec這裡不需要傳入引數了,因為前面已經find 拿到結果了
goodsModel.exec(function (err,doc) {
if(err) {
res.json({
status:'1',
msg:err.message
});
} else {
// 如果沒有報錯就把結果輸出
res.json({
status:'0',
msg:'',
result:{
count: doc.length,
list: doc
}
});
}
});
});
// 加入購物車
router.post("/addCart", function (req,res,next) {
// post獲取前端引數需要使用req.body.屬性名
var userId = '100000077',productId = req.body.productId;
var User = require('../models/user'); // 獲取使用者模型
// 查詢當前使用者
User.findOne({userId:userId}, function (err,userDoc) {
if(err) {
res.json({
status:"1",
msg:err.message
})
}else{
console.log("userDoc:"+userDoc);
if(userDoc) {
let goodsItem = '';
// 遍歷購物車列表查詢有沒有此產品
userDoc.cartList.forEach(function (item) {
if(item.productId == productId){ // 如果購物車列表已經有了該商品,只將此商品數量加1
goodsItem = item;
item.productNum ++;
}
});
if(goodsItem){ // 如果此商品購物車裡面已經有了,那麼就更新一下productNum
userDoc.save(function (err2,doc2) {
if(err2) {
res.json({
status:"1",
msg:err2.message
})
}else{
res.json({
status:'0',
msg:'',
result:'suc'
})
}
});
} else { // 如果此商品購物車列表沒有,那麼則將此商品新增至購物車列表
Goods.findOne({productId:productId},function (err1,doc) {
if(err1) {
res.json({
status:"1",
msg:err1.message
})
}else{
if(doc) {
doc.productNum = 1;
doc.checked = 1;
userDoc.cartList.push(doc); // 將資料新增
userDoc.save(function (err2,doc2) {
if(err2) {
res.json({
status:"1",
msg:err2.message
})
}else{
res.json({
status:'0',
msg:'',
result:'suc'
})
}
});
}
}
});
}
}
}
})
});
// 通過module.exports進行輸出,這樣才能載入到
module.exports = router;
vue前端GoodList.vue 商品列表及新增購物車邏輯
<template>
<div>
<nav-header></nav-header>
<nav-bread>
<span>Goods</span>
</nav-bread>
<div class="accessory-result-page accessory-page">
<div class="container">
<div class="filter-nav">
<span class="sortby">Sort by:</span>
<a href="javascript:void(0)" class="default cur">Default</a>
<a @click="showFilterPop" href="javascript:void(0)" class="price">
Price
<svg class="icon icon-arrow-short"><use xlink:href="#icon-arrow-short"></use></svg>
</a>
<a href="javascript:void(0)" class="filterby stopPop" @click="showFilterPop">Filter by</a>
</div>
<div class="accessory-result">
<!-- filter -->
<div class="filter stopPop" id="filter">
<dl class="filter-price">
<dt>Price:</dt>
<dd><a href="javascript:void(0)" v-bind:class="{'cur':priceChecked=='all'}" @click="priceChecked='all'">All</a></dd>
<dd v-for="(price,index) in priceFilter" :key="index">
<a href="javascript:void(0)" @click="setPriceFilter(index)" v-bind:class="{'cur':priceChecked==index}">{{ price.startPrice }}-{{ price.endPrice }}</a>
</dd>
</dl>
</div>
<!-- search result accessories list -->
<div class="accessory-list-wrap">
<div class="accessory-list col-4">
<ul>
<li v-for="(item,index) in goodsList" :key="index">
<div class="pic">
<a href="#"><img v-lazy="'/static/'+item.productImage" alt=""></a>
</div>
<div class="main">
<div class="name">{{item.productName}}</div>
<div class="price">{{item.salePrice}}</div>
<div class="btn-area">
<a href="javascript:;" class="btn btn--m" @click="addCart(item.productId)">加入購物車</a>
</div>
</div>
</li>
</ul>
<div class="load-more" v-infinite-scroll="loadMore" infinite-scroll-disabled="busy" infinite-scroll-distance="30">
<img src="./../assets/loading-spinning-bubbles.svg" alt="" v-show="loading">
</div>
</div>
</div>
</div>
</div>
</div>
<!-- <div class="md-overlay" v-show="overLayFlag" @click="closePop"></div> -->
<nav-footer></nav-footer>
</div>
</template>
<script>
import './../assets/css/base.css'
import './../assets/css/product.css'
import './../assets/css/checkout.css'
import './../assets/css/login.css'
import NavHeader from '@/components/NavHeader.vue'
import NavFooter from '@/components/NavFooter.vue'
import NavBread from '@/components/NavBread.vue'
import axios from 'axios'
export default {
data () {
return {
goodsList: [],
sortFlag: true, // 排序欄位
page:1, // 預設頁
pageSize: 8, // 預設一頁顯示8條資料
busy:true,
loading:true,
// priceLevel:this.priceChecked, // 篩選選擇價格
priceFilter:[
{
startPrice:'0.00',
endPrice:'100.00'
},
{
startPrice:'100.00',
endPrice:'500.00'
},
{
startPrice:'500.00',
endPrice:'1000.00'
},
{
startPrice:'1000.00',
endPrice:'5000.00'
}
],
priceChecked:'all'
// filterBy:false,
// overLayFlag:false
}
},
components: {
NavHeader,
NavFooter,
NavBread
},
mounted () {
this.getGoodList();
},
methods: {
getGoodList (flag) {
var param = { // 分頁及排序引數
page:this.page,
pageSize: this.pageSize,
sort: this.sortFlag?1:-1, // 升序是1 降序是-1
priceLevel: this.priceChecked
}
this.loading = true;
axios.get("/goods", {params:param}).then((result)=>{
let res = result.data;
this.loading = false;
if(res.status=="0"){
if(flag){ // 如果是分頁需要累計
// 將陣列進行串聯起來 concat表示將陣列連線起來
this.goodsList = this.goodsList.concat(res.result.list);
if(res.result.count == 0){
this.busy = true;
} else {
this.busy = false;
}
} else { // 普通的請求
this.goodsList = res.result.list;
this.busy = false;
}
} else {
this.goodsList = [];
}
});
},
showFilterPop() { // 排序
// this.filterBy = true;
// this.overLayFlag = true;
this.sortFlag = ! this.sortFlag; // 點選後升序降序切換
this.page = 1; // 點選升降序後預設從第一頁顯示
this.getGoodList(); // 重新載入一次
},
loadMore () {
this.busy = true; // 在請求成功之前禁止再滾動載入
// 滑鼠滾動實在太快了,滾動一秒鐘可能有上千個請求,這樣對伺服器壓力太大 因此必須要通過setTimeout來控制
// 只有第一個請求結束以後才能請求第二個
setTimeout(() => {
this.page++; // 滾動之後要給page++
this.getGoodList(true);
}, 500);
},
setPriceFilter(index) { // 價格過濾
this.priceChecked = index;
this.page = 1; // 價格過濾後分頁從第一頁重新開始
this.getGoodList();
// this.closePop();
},
addCart(productId) { // 新增購物車
axios.post("/goods/addCart",{
productId:productId
}).then((res)=>{
if(res.status==200){
alert("加入成功");
}else{
alert("msg:"+res.msg);
}
});
}
}
}
</script>