实现功能为:
在商品详情页面,选择想要购买的数量,点击“加入购物车”按钮,实现右上角的购物车数量增加,并且页面其他信息保持不变。
一般处理按钮点击后,需要重新查询刷新整个页面的信息,但是很多需求只是刷新局部或一小部分信息,因此可以通过发送Ajax请求实现,注意ajax请求都是在后台运行的,前台不会展示运行的过程。
Ajax请求过程为:
1. 前端页面发起ajax请求(这里使用jQuery)将数据传递给后端
2. 后端执行请求地址相对应的视图函数,返回json内容
3. ajax执行相应的回调函数。接收返回的json数据并执行后续操作
编辑详情页面的前端js代码
1、jQuery获取标签元素对象为:$('.classname')
2、获取子标签:$('.classname').children('标签名')
3、获取文本内容为:.text()
4、获取值属性为:.val()
5、设置标签值为在获取值的方法中加入参数,该参数就是想要设置成为的值
6、注意点击事件如果想要调用其他的方法,不能直接写成.click(function_name()),还是得写成.click(function (){function_name()}),即在匿名方法中再调用其他的方法
7、isNaN() 函数可用于判断其参数是否是 NaN,该值表示一个非法的数字。
8、发起Ajax请求写法,$.post('/cart/add/', parameter, function(data){....}) 第一个参数为请求提交的地址,第二个参数为传给后台的数据,第三个参数为回调函数,即后台处理完成后,会调用这个回调函数,参数data为后台返回的数据,在回调函数中,使用返回的数据重新设置页面的部分数据
{% block endfiles %} <div class="add_jump"></div> <script type="text/javascript" src="{% static 'js/jquery-1.12.4.min.js'%}"></script> <script type="text/javascript"> //计算总价 update_goods_amout() function update_goods_amout(){ //获取单价 price = $('.show_pirze').children('em').text() //获取数量 count = $('.num_show').val() //计算总价 amount = price * count //刷新界面总价 $('.total').children('em').text(amount.toFixed(2)+'元') } //加号点击事件 $('.add').click(function(){ calculate(1) }) //减号点击事件 $('.minus').click(function(){ calculate(-1) }) //加减数量 function calculate(num){ //获取原数量 count = $('.num_show').val() //+-1 count = parseInt(count) + num if (count <=0){ count = 1 } //刷新界面 $('.num_show').val(count) //更新总价 update_goods_amout() } //手动输入商品数量 $('.num_show').blur(function(){ //获取数量 count = $(this).val() //校验数量, if (isNaN(count) || count.trim().length==0 || parseInt(count) <=0){ //刷新数量 count = 1 $(this).val(parseInt(count)) } //更新总价 update_goods_amout() }) //获取add_cart div元素左上角的坐标 var $add_x = $('#add_cart').offset().top; var $add_y = $('#add_cart').offset().left; //获取show_count div元素左上角的坐标 var $to_x = $('#show_count').offset().top; var $to_y = $('#show_count').offset().left; //点击加入购物车的click事件 $('#add_cart').click(function(){ //获取数量 count = $('.num_show').val() //获取商品ID,手动给加入购物车按钮新增一个属性goods_id goods_id = $(this).attr('goods_id') //csrf验证信息 csrf = $('input[name="csrfmiddlewaretoken"]').val() //组织参数 parameter = { 'goods_id': goods_id, 'count': count, 'csrfmiddlewaretoken': csrf } //发起Ajax请求,第三个参数function为回调函数 $.post('/cart/add/', parameter, function(data){ if (data.status == 'S'){ //添加成功 //购物车加入成功的动态效果 $(".add_jump").css({'left':$add_y+80,'top':$add_x+10,'display':'block'}) $(".add_jump").stop().animate( {'left': $to_y+7, 'top': $to_x+7}, "fast", function() { $(".add_jump").fadeOut('fast',function(){ //刷新右上角购物车数量 $('#show_count').html(data.cart_count); }); }); } else{ //添加失败 alert(data.errmsg) } }) }) </script> {% endblock endfiles %}
编辑请求提交的URL
编辑cart应用的urls.py文件
from django.urls import path from .views import CartView, CartAddView urlpatterns = [ path('add/', CartAddView.as_view(), name='add'), path('', CartView.as_view(), name='cart'), ]
编辑处理请求的类视图
编辑cart应用的view.py文件
1、这里判断用户是否登录时,是手动写的校验,而不是像user应用中继承LoginRequiredMixin,原因是因为如果继承了LoginRequiredMixin,谷歌浏览器按F12打开后台运行情况查看,后台确实会访问重定向到的登录页面,但是由于这里提交的是Ajax请求,前台并不会跳转成登录页面,所以用户体验来说是这个跳转是无效的。
2、获取前台传过来的商品和数量,校验成功后,将其添加至购物车redis数据库中,然后返回新的购物车数据
3、返回的是JsonResponse对象,返回值内容为json格式
from django.views.generic import View from django.http import JsonResponse from goods.models import Goods from django_redis import get_redis_connection class CartAddView(View): '''加入购物车处理视图''' def post(self, request): user = request.user context = { 'status': 'E', 'errmsg': '' } # 判断是否登录 if not user.is_authenticated: context['errmsg'] = '用户未登录!' return JsonResponse(context) # 接收数据 goods_id = request.POST.get('goods_id') count = request.POST.get('count') # 校验数据 # 数据是否完整 if not all([goods_id, count]): context['errmsg'] = '数据不完整!' return JsonResponse(context) # 商品是否存在 try: goods_id = int(goods_id) goods = Goods.objects.get(id=goods_id) except Exception as e: context['errmsg'] = '用户未登录!' return JsonResponse(context) # 数量格式是否正确 try: count = int(count) except Exception as e: context['errmsg'] = '商品数量格式不正确!' return JsonResponse(context) # 逻辑处理:添加购物车 # 连接redis connect = get_redis_connection('default') cart = 'cart_%d'%(user.id) # 获取原购物车中goods_id的数量 old_count = connect.hget(cart, goods_id) if old_count: count += int(old_count) # 判断是否超过库存 if count > goods.onhand: context['errmsg'] = '超出库存数量!' return JsonResponse(context) # 将新数量保存至数据库 connect.hset(cart, goods_id, count) # 获取新购物车数量 cart_count = connect.hlen(cart) # 返回数据 context['status'] = 'S' context['cart_count'] = cart_count return JsonResponse(context)