目錄:
- 完善加入購物車的提示頁
- 完善購物車的刪除
- 細節(jié)說明
之前有寫了一個購物車,將會員和游客,分開.會員加車存數(shù)據(jù)庫,游客加車存cookie.但是這個系統(tǒng),加入購物車就會跳轉(zhuǎn)至購物車頁面.但是在京東等電商當中,我發(fā)現(xiàn)他們并不是這樣處理的
京東會先跳往一個加入購物車成功的一個頁面.這樣做有什么好處呢
- 可以誘導(dǎo)用戶繼續(xù)購物
- 可以讓cookie寫入成功(這個在后面會有詳細說明)
- 可以不用將某件商品加入購物車,而直接進入購物車(這算是個bug的修復(fù))
首先我們需要明白,做這樣的購物車優(yōu)化,我們需要些什么.
- 首先我們需要一個前端頁面代碼,這個不是今天的重點,我就不說了
我們直接來看看流程圖
我們按照這個思路,寫了一個加入購物車提示頁方法
/**
* 提示加車成功頁面
*/
public function actionCarttips()
{
//接收前臺數(shù)據(jù)
$data = Yii::$app->request->get();
//判斷用戶是否登陸
if (Yii::$app->user->isGuest) {
//如果沒有登陸,調(diào)用未登陸加車方法
if (!$this->guestAddCart($data)) {
echo '數(shù)據(jù)出錯,稍后再試游客';
exit;
}
} else {
//如果登陸,調(diào)用登陸加車方法
if (!$this->memberAddCart($data)) {
echo '數(shù)據(jù)出錯,稍后再試';
exit;
}
}
//渲染加車提示頁面,傳入id,繼續(xù)購物使用
return $this->render('CartTips', ['goods_id' => $data['goods_id']]);
}
在這段代碼中,我在這個控制器里之前就已經(jīng)封裝好了,游客和會員兩個不同的加入購物車方法.
由于商品詳情頁,我使用的是頁面靜態(tài)化,所有只能使用get傳值來避免csrf驗證
get接收到值過后,傳給相應(yīng)的方法,完成加車,渲染加車提示頁面.
這里有個小細節(jié),我們傳遞了一個goods_id到前端頁面,這里是為了讓用戶點擊繼續(xù)購物的時候能夠直接跳回之前的那個商品頁面.讓用戶體驗更完善.
下面我們來看看購物車里商品的刪除,一個購物車,必須得有刪除功能,我們不能規(guī)定用戶加入購物車后就不能刪除,也許是用戶手滑或則別的什么原因,購物車里必須有刪除.
這里我們選擇的是異步請求刪除
之所以要選擇異步是因為,異步刪除不刷新頁面感覺比較高級.還有就是異步請求,只會傳遞數(shù)據(jù),并不會重新加載靜態(tài)資源.這樣反應(yīng)也會比較快
下面我們來看看刪除購物車的流程
我們先來看前端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="對應(yīng)的商品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發(fā)送到后臺接口,獲取json結(jié)果
$.getJSON(
'<?=\yii\helpers\Url::to(['goods/delcart'])?>',
{'goods_id': goods_id},
function (data) {
if (data.status) {
//成功
layer.msg(data.message, {icon: 1});
//刪除dom節(jié)點
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代碼,使用了兩個小技術(shù).一個是事件委派,一個是ajax異步請求技術(shù).這里就不細講了.我們重點來看看后臺的接口方法
/**
* 刪除購物車中的數(shù)據(jù)接口
*/
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中的數(shù)據(jù)
$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{
//會員
//查出數(shù)據(jù)庫中這個商品的對象
$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;
}
//修改這條商品的狀態(tài)
$cartModel->status=0;
$cartModel->save();
echo json_encode(['status' => 1, 'message' => '刪除成功']);
}
}
這里首先將游客和會員分開,使用Yii::$app->user->isGuset來判斷
- 游客的話,要復(fù)雜一點,我們將cookie里的數(shù)據(jù)取出,然后找到相應(yīng)的goods_id對應(yīng)的那條數(shù)據(jù),將它刪除,隨后,又將剩下的數(shù)據(jù)再序列化后,再寫入cookie.返回json化的執(zhí)行結(jié)果
- 會員我們是選擇查出購物車表中的含有當前用戶和含有g(shù)oods_id的一條數(shù)據(jù)對象
將這一對象的狀態(tài)改為0,這樣完成的刪除,同樣的,返回一條json化的執(zhí)行結(jié)果
之前有提到要在購物車中加上提示頁面,對寫入cookie更友好.
我們都知道,cookie是存儲在瀏覽器中的數(shù)據(jù).當我們的代碼執(zhí)行到寫入一條cookie時,并沒有真正的寫入,原因是我們必須在response,也就是渲染頁面時候才能寫入到cookie,在之前的版本中.我發(fā)現(xiàn),當我渲染頁面,在cookie中取值,并沒有剛加入的cookie數(shù)據(jù).
當時我的解決方案就是,在渲染頁面中把get到的值,合并到之前的cookie中,來解決cookie寫入慢半拍的問題,可是這一解決方案,始終感覺不夠優(yōu)雅,數(shù)據(jù)來源復(fù)雜化了.
所有采用中間加一頁的方法的話,就在渲染提示頁的時候就成功加入cookie,當用戶這是點擊購物車時候,我們直接到cookie中取值,就可與取到完整的數(shù)據(jù)