1. 程式人生 > >加入購物車功能實現

加入購物車功能實現

在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>