1. 程式人生 > >樂優商城(三十二)——購物車

樂優商城(三十二)——購物車

目錄

一、搭建購物車微服務

1.1 建立module

1.2 pom依賴

1.3 配置檔案

1.4 啟動類

二、購物車功能分析

2.1 需求

2.2 流程圖

三、未登入購物車

3.1 準備

3.1.1 購物車的資料結構

3.1.2 web本地儲存

3.1.3 獲取num

3.2 新增購物車

3.2.1 點選事件

3.2.2 獲取數量、新增購物車

3.3 查詢購物車

3.3.1 校驗使用者登入

3.3.2 查詢購物車

3.3.3 渲染到頁面

3.4 修改數量

3.5 刪除商品

3.6 選中商品

3.6.1 選中一個

3.6.2 全部選中

3.6.3 初始化全選

3.6.4 總價格

3.6.5 總數量


一、搭建購物車微服務

1.1 建立module

1.2 pom依賴

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>leyou</artifactId>
        <groupId>com.leyou.parent</groupId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.leyou.cart</groupId>
    <artifactId>leyou-cart</artifactId>
    <version>1.0.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
    </dependencies>
</project>

1.3 配置檔案

server:
  port: 8088
spring:
  application:
    name: cart-service
  redis:
    host: 192.168.19.121
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
    registry-fetch-interval-seconds: 10
  instance:
    instance-id: ${spring.application.name}:${server.port}
    prefer-ip-address: true  #當你獲取host時,返回的不是主機名,而是ip
    ip-address: 127.0.0.1
    lease-expiration-duration-in-seconds: 10 #10秒不傳送九過期
    lease-renewal-interval-in-seconds: 5 #每隔5秒發一次心跳

1.4 啟動類

package com.leyou.cart;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

/**
 * @Author: 98050
 * @Time: 2018-10-24 20:46
 * @Feature:購物車啟動器
 */
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class LyCartApplication {

    public static void main(String[] args) {
        SpringApplication.run(LyCartApplication.class,args);
    }
}

二、購物車功能分析

2.1 需求

需求描述:

  • 使用者可以在登入狀態下將商品新增到購物車

    • 放入資料庫

    • 放入redis(採用)

  • 使用者可以在未登入狀態下將商品新增到購物車

    • 放入localstorage

  • 使用者可以使用購物車一起結算下單

  • 使用者可以查詢自己的購物車

  • 使用者可以在購物車中修改購買商品的數量。

  • 使用者可以在購物車中刪除商品。

  • 在購物車中展示商品優惠資訊

  • 提示購物車商品價格變化

2.2 流程圖

這幅圖主要描述了兩個功能:新增商品到購物車、查詢購物車。

新增商品:

  • 判斷是否登入

    • 是:則新增商品到後臺Redis中

    • 否:則新增商品到本地的Localstorage

無論哪種新增,完成後都需要查詢購物車列表:

  • 判斷是否登入

    • 否:直接查詢localstorage中資料並展示

    • 是:已登入,則需要先看本地是否有資料,

      • 有:需要提交到後臺新增到redis,合併資料,而後查詢

      • 否:直接去後臺查詢redis,而後返回

三、未登入購物車

3.1 準備

3.1.1 購物車的資料結構

首先分析一下未登入購物車的資料結構。

我們看下頁面展示需要什麼資料:

因此每一個購物車資訊,都是一個物件,包含:

{
    skuId:2131241,
    title:"小米6",
    image:"",
    price:190000,
    num:1,
    ownSpec:"{"機身顏色":"陶瓷黑尊享版","記憶體":"6GB","機身儲存":"128GB"}"
}

另外,購物車中不止一條資料,因此最終會是物件的陣列。即:

[
    {...},{...},{...}
]

3.1.2 web本地儲存

知道了資料結構,下一個問題,就是如何儲存購物車資料。前面分析過,可以使用Localstorage來實現。Localstorage是web本地儲存的一種,那麼,什麼是web本地儲存呢?

什麼是web本地儲存

web本地儲存主要有兩種方式:

  • LocalStorage:localStorage 方法儲存的資料沒有時間限制。第二天、第二週或下一年之後,資料依然可用。

  • SessionStorage:sessionStorage 方法針對一個 session 進行資料儲存。當用戶關閉瀏覽器視窗後,資料會被刪除。

LocalStorage的用法

語法非常簡單:

localStorage.setItem("key","value"); // 儲存資料
localStorage.getItem("key"); // 獲取資料
localStorage.removeItem("key"); // 刪除資料

注意:localStorage和SessionStorage都只能儲存字串

不過,在common.js中,已經對localStorage進行了簡單的封裝:

示例:

3.1.3 獲取num

新增購物車需要知道購物的數量,所以需要獲取數量大小。在Vue中定義num,儲存數量:

然後將num與頁面的input框繫結,同時給+-的按鈕繫結事件:

編寫方法:

3.2 新增購物車

3.2.1 點選事件

商品詳情頁:

現在點選加入購物車會跳轉到購物車成功頁面。

不過不這麼做,先繫結點選事件,然後實現新增購物車功能。

addCart方法中判斷使用者的登入狀態:

            addCart(){
                ly.http.get("/auth/verify").then(res => {
                    //已經登入傳送訊息到後臺,儲存到redis中
                }).catch(() =>{
                    //未登入儲存在瀏覽器本地localStorage中
                })
            }

3.2.2 獲取數量、新增購物車

addCart(){
                ly.http.get("/auth/verify").then(res => {
                    //已經登入傳送訊息到後臺,儲存到redis中
                }).catch(() =>{
                    //未登入儲存在瀏覽器本地localStorage中
                    //1.查詢本地購物車
                    let carts = ly.store.get("carts") || [];
                    let cart = carts.find(c => c.skuId === this.sku.id);
                    //2.判斷是否存在
                    if (cart){
                        //3.存在更新數量
                        cart.num += this.num;
                    } else{
                        //4.不存在,新增
                        cart={
                            skuId:this.sku.id,
                            title:this.sku.title,
                            price:this.sku.price,
                            image:this.sku.image,
                            num:this.num,
                            ownSpec:JSON.stringify(this.ownSpec)
                        };
                        carts.push(cart);
                    }
                    //5.把carts寫回到localStorage
                    ly.store.set("carts",carts);
                    //6.跳轉
                    window.location.href = "http://www.leyou.com/cart.html";
                });
            }

結果:

新增完成後,頁面會跳轉到購物車結算頁面:cart.html

3.3 查詢購物車

3.3.1 校驗使用者登入

因為校驗使用者會多次進行,所以在common.js中將其封裝為一個方法:

然後呼叫:

3.3.2 查詢購物車

頁面載入時,就應該去查詢購物車。

var cartVm = new Vue({
        el: "#cartApp",
        data: {
            ly,
            carts:[], //購物車資料
        },
        components: {
            shortcut: () => import("/js/pages/shortcut.js")
        },
        created(){
            this.loadCarts();
        },
        methods:{
            loadCarts(){
                //1.先判斷登入狀態
                ly.verifyUser().then(() => {
                    //2.已經登入
                }).catch(() => {
                    //3.未登陸
                    this.carts = ly.store.get("carts") || [];
                })
            }
        }
    })

重新整理頁面,檢視資料:

3.3.3 渲染到頁面

效果:

3.4 修改數量

給頁面的 +-繫結點選事件,修改num 的值:

            increment(c){
                c.num++;
                ly.verifyUser().then(() =>{
                    //已經登入,向後臺發起請求
                }).catch(() => {
                    //未登入,直接操作本地資料庫
                    ly.store.set("carts",this.carts);
                })
            },
            decrement(c){
                if (c.num <= 1){
                    return;
                } 
                c.num--;
                ly.verifyUser().then(() =>{
                    //已經登入,向後臺發起請求
                }).catch(() => {
                    //未登入,直接操作本地資料庫
                    ly.store.set("carts",this.carts);
                })
            },

3.5 刪除商品

給刪除按鈕繫結事件:

deleteCart(i){
                ly.verifyUser().then(() =>{
                    //已經登入,向後臺發起請求
                }).catch(() => {
                    //未登入,直接操作本地資料庫
                    this.carts.splice(i,1);
                    ly.store.set("carts",this.carts);
                })
}

3.6 選中商品

在頁面中,每個購物車商品左側,都有一個複選框,使用者可以選擇部分商品進行下單,而不一定是全部:

定義一個變數,記錄所有被選中的商品:

3.6.1 選中一個

給商品前的複選框與selected繫結,並且指定其值為當前購物車商品:

3.6.2 全部選中

分析

頁面方法繫結

上:

中:

下:

程式碼

loadCarts: function () {
                //1.先判斷登入狀態
                ly.verifyUser().then(() => {
                    //2.已經登入
                }).catch(() => {
                    //3.未登陸
                    this.carts = ly.store.get("carts") || [];
                    this.selected = this.carts;
                    this.$refs.selectAllTop.checked = true;
                    this.$refs.selectAllBottom.checked = true;
                })
            }

初始化是全選的。

            selectAll(){
                if(this.selected.length !== ly.store.get("carts").length){
                    this.selected = this.carts;
                }else  {
                    this.selected = [];
                }
            },
            selectSingle(){

                console.log(this.selected.length);
                console.log(ly.store.get("carts").length);

                if(this.selected.length !== ly.store.get("carts").length - 1){
                    this.$refs.selectAllTop.checked=false;
                    this.$refs.selectAllBottom.checked=false;
                }else{
                    this.$refs.selectAllTop.checked=true;
                    this.$refs.selectAllBottom.checked=true;
                }
            }

注意:為什麼要減1?

因為selected和商品選擇按鈕是雙向繫結,當單擊按鈕時,獲取的selected的長度是改變前的長度,所以要進行修正,可自行實驗。

3.6.3 初始化全選

載入完成購物車查詢後,初始化全選:

3.6.4 總價格

編寫計算屬性,計算選中商品的總價格:

        computed:{
          totalPrice(){
              return ly.formatPrice(this.selected.reduce((c1,c2) => c1+c2.num*c2.price,0))
          }
        }

3.6.5 總數量

編寫計算屬性:

totalNum(){
              return this.selected.reduce((c1,c2) => c1+c2.num,0);
          }

效果: