目录:
- 完善加入购物车的提示页
- 完善购物车的删除
- 细节说明
之前有写了一个购物车,将会员和游客,分开.会员加车存数据库,游客加车存cookie.但是这个系统,加入购物车就会跳转至购物车页面.但是在京东等电商当中,我发现他们并不是这样处理的
京东会先跳往一个加入购物车成功的一个页面.这样做有什么好处呢
- 可以诱导用户继续购物
- 可以让cookie写入成功(这个在后面会有详细说明)
- 可以不用将某件商品加入购物车,而直接进入购物车(这算是个bug的修复)
首先我们需要明白,做这样的购物车优化,我们需要些什么.
- 首先我们需要一个前端页面代码,这个不是今天的重点,我就不说了
我们直接来看看流程图
我们按照这个思路,写了一个加入购物车提示页方法
/**
* 提示加车成功页面
*/
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到前端页面,这里是为了让用户点击继续购物的时候能够直接跳回之前的那个商品页面.让用户体验更完善.
下面我们来看看购物车里商品的删除,一个购物车,必须得有删除功能,我们不能规定用户加入购物车后就不能删除,也许是用户手滑或则别的什么原因,购物车里必须有删除.
这里我们选择的是异步请求删除
之所以要选择异步是因为,异步删除不刷新页面感觉比较高级.还有就是异步请求,只会传递数据,并不会重新加载静态资源.这样反应也会比较快
下面我们来看看删除购物车的流程
我们先来看前端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(
'<?=\yii\helpers\Url::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中取值,就可与取到完整的数据