完善購物車系統

勃起狂奔者發表於2017-07-14

目錄:

  1. 完善加入購物車的提示頁
  2. 完善購物車的刪除
  3. 細節說明

之前有寫了一個購物車,將會員和遊客,分開.會員加車存資料庫,遊客加車存cookie.但是這個系統,加入購物車就會跳轉至購物車頁面.但是在京東等電商當中,我發現他們並不是這樣處理的

圖片來自京東

京東會先跳往一個加入購物車成功的一個頁面.這樣做有什麼好處呢

  • 可以誘導使用者繼續購物
  • 可以讓cookie寫入成功(這個在後面會有詳細說明)
  • 可以不用將某件商品加入購物車,而直接進入購物車(這算是個bug的修復)

首先我們需要明白,做這樣的購物車優化,我們需要些什麼.

  • 首先我們需要一個前端頁面程式碼,這個不是今天的重點,我就不說了

我們直接來看看流程圖

購物車優化.png

我們按照這個思路,寫了一個加入購物車提示頁方法

    /**
     * 提示加車成功頁面
     */
    public function actionCarttips()
    {
        //接收前臺資料
        $data = Yii::$app->request->get();
        //判斷使用者是否登陸
        if (Yii::$app->user->isGuest) {
            //如果沒有登陸,呼叫未登陸加車方法
            if (!$this->guestAddCart($data)) {
                echo `資料出錯,稍後再試遊客`;
                exit;
            }
        } else {
            //如果登陸,呼叫登陸加車方法
            if (!$this->memberAddCart($data)) {
                echo `資料出錯,稍後再試`;
                exit;
            }
        }
        //渲染加車提示頁面,傳入id,繼續購物使用
        return $this->render(`CartTips`, [`goods_id` => $data[`goods_id`]]);
    }

在這段程式碼中,我在這個控制器裡之前就已經封裝好了,遊客和會員兩個不同的加入購物車方法.
由於商品詳情頁,我使用的是頁面靜態化,所有隻能使用get傳值來避免csrf驗證
get接收到值過後,傳給相應的方法,完成加車,渲染加車提示頁面.
這裡有個小細節,我們傳遞了一個goods_id到前端頁面,這裡是為了讓使用者點選繼續購物的時候能夠直接跳回之前的那個商品頁面.讓使用者體驗更完善.


下面我們來看看購物車裡商品的刪除,一個購物車,必須得有刪除功能,我們不能規定使用者加入購物車後就不能刪除,也許是使用者手滑或則別的什麼原因,購物車裡必須有刪除.

這裡我們選擇的是非同步請求刪除
之所以要選擇非同步是因為,非同步刪除不重新整理頁面感覺比較高階.還有就是非同步請求,只會傳遞資料,並不會重新載入靜態資源.這樣反應也會比較快

下面我們來看看刪除購物車的流程

購物車刪除.png

我們先來看前端jquery程式碼

<script type="text/javascript" src="<?= Yii::$app->params[`jquery`] ?>"></script>
<script type="text/javascript" src="/statics/plug/layer/layer/layer.js"></script>
<script type="text/javascript" src="/statics/js/cart1.js"></script>
<script type="text/javascript">
    $(function () {
        //使用事件委派,委派到刪除的a標籤上.a標籤有兩個屬性,一個是class="del",一個是goods_id="對應的商品id"
        $("#cart_content").on(`click`, ".del", function (event) {
            //獲取到id
            var goods_id = $(event.target).attr(`goods_id`);
            //通過尋找父級物件.找到點選刪除的那一行tr
            var dom = $(event.target).parents(`.num_tr`);
            if (confirm(`您真的要刪除這個商品嗎`)) {
                //將id傳送到後臺介面,獲取json結果
                $.getJSON(
                    `<?=yiihelpersUrl::to([`goods/delcart`])?>`,
                    {`goods_id`: goods_id},
                    function (data) {
                        if (data.status) {
                            //成功
                            layer.msg(data.message, {icon: 1});
                            //刪除dom節點
                            dom.remove();
                           //重新計算總價
                            var price = 0;
                            if ($(".onePrice") !== undefined) {
                                $(`.onePrice`).each(function (i, v) {
                                    price += Number($(v).text());
                                });
                            }
                            $("#total").text(price);
                        } else {
                            //彈出小標籤提示
                            layer.msg(data.message, {icon: 2});
                        }
                    }
                )
            }
        })
    })
</script>

前段jq程式碼,使用了兩個小技術.一個是事件委派,一個是ajax非同步請求技術.這裡就不細講了.我們重點來看看後臺的介面方法

    /**
     * 刪除購物車中的資料介面
     */
    public function actionDelcart()
    {
        $goods_id = Yii::$app->request->get(`goods_id`);
        if (Yii::$app->user->isGuest) {
            //遊客
            //獲取cookie
            $cookieobj = Yii::$app->request->cookies;
            $cookieValue = $cookieobj->getValue(`cart_cookie`);
            if (empty($cookieValue)) {
                echo json_encode([`status` => 0, `message` => `購物車中沒有這個商品`]);
                exit;
            }
            //反序列化cookie中的資料
            $cartArr = unserialize($cookieValue);
            foreach ($cartArr as $key => $value) {
                if ($key == $goods_id) {
                    unset($key);
                }
            }
            //序列化
            $serArr = serialize($cartArr);
            //將cookie寫入
            Yii::$app->response->cookies->add(new Cookie([
                `name` => `cart_cookie`,
                `value` => $serArr
            ]));
            echo json_encode([`status` => 1, `message` => `刪除成功`]);
        }
        else{
            //會員
            //查出資料庫中這個商品的物件
            $cartModel=Cart::findOne([`goods_id`=>$goods_id,`user_id`=>Yii::$app->user->identity->getId(),`status`=>2]);
            if (empty($cartModel)) {
                echo json_encode([`status` => 0, `message` => `購物車中沒有這個商品`]);
                exit;
            }
            //修改這條商品的狀態
            $cartModel->status=0;
            $cartModel->save();
            echo json_encode([`status` => 1, `message` => `刪除成功`]);
        }
    }

這裡首先將遊客和會員分開,使用Yii::$app->user->isGuset來判斷

  • 遊客的話,要複雜一點,我們將cookie裡的資料取出,然後找到相應的goods_id對應的那條資料,將它刪除,隨後,又將剩下的資料再序列化後,再寫入cookie.返回json化的執行結果
  • 會員我們是選擇查出購物車表中的含有當前使用者和含有goods_id的一條資料物件
    將這一物件的狀態改為0,這樣完成的刪除,同樣的,返回一條json化的執行結果

之前有提到要在購物車中加上提示頁面,對寫入cookie更友好.

我們都知道,cookie是儲存在瀏覽器中的資料.當我們的程式碼執行到寫入一條cookie時,並沒有真正的寫入,原因是我們必須在response,也就是渲染頁面時候才能寫入到cookie,在之前的版本中.我發現,當我渲染頁面,在cookie中取值,並沒有剛加入的cookie資料.

當時我的解決方案就是,在渲染頁面中把get到的值,合併到之前的cookie中,來解決cookie寫入慢半拍的問題,可是這一解決方案,始終感覺不夠優雅,資料來源複雜化了.

所有采用中間加一頁的方法的話,就在渲染提示頁的時候就成功加入cookie,當使用者這是點選購物車時候,我們直接到cookie中取值,就可與取到完整的資料


相關文章