【Vue+DRF生鲜电商】11.Vue展示左侧分类、面包屑、排序、商品列表、分页

欢迎访问我的博客专题

源码可访问 Github 查看

通过顶部导航显示的左侧分类,和通过搜索显示的左侧分类,整个格式是相同的,所以它们用的同一个Vue组件。但是它们还是有一定的区别:

  • 点击顶部导航,左侧的分类就是显示该一级分类下的所有子分类(包括所有二级分类和二级分类对应的三级分类)
  • 搜索显示的分类,只显示了二级分类和一级分类,也就是说,搜索某一个商品,可以获取该商品对应的分类和对应的子分类

获取所有数据getAllData()

list/list.vue 中getAllData()获取所有数据

getAllData() {
    console.log('list/list.vue 获取左侧菜单');
    console.log(this.$route.params);
    var curloc_id = '';  //当前点击分类的id
    if (this.$route.params.id) {
        //如果能获取到id值,那么就是点击分类
        this.top_category = this.$route.params.id;
        this.pageType = 'list';
        this.getMenu(this.top_category); // 获取左侧菜单列表
        curloc_id = this.$route.params.id;
    } else {
        this.getMenu(null); // 获取左侧菜单列表
        this.pageType = 'search';
        this.searchWord = this.$route.params.keyword;
        curloc_id = ''
    }

    this.getCurLoc(curloc_id); // 获取当前位置
    this.getListData(); //获取产品列表
    this.getPriceRange(); // 获取价格区间
},

这个函数由于判断是点击分类还是搜索进入。

区别导航和搜索显示左侧分类getMenu(id)

list/list.vue 获取菜单

getMenu(id) {
    if (id != null) {
        getCategory({
            id: this.$route.params.id
        }).then((response) => {
            this.cateMenu = response.data.sub_category;
            console.log('list/list.vue 获取分类数据:');
            console.log(response.data);
            this.currentCategoryName = response.data.name;  //获取当前分类的名称
            this.currentCategoryID = response.data.id;  //获取请求的一级分类的ID
            this.isObject = true
            //console.log(response.data)
        }).catch(function (error) {
            console.log(error);
        });
    } else {
        getCategory({}).then((response) => {
            this.cateMenu = response.data;
            console.log('list/list.vue 获取分类数据:');
            console.log(response.data);
            this.isObject = false
        }).catch(function (error) {
            console.log(error);
        });
    }
},

传递某个一级分类id,通过getCategory方法获取该分类详情(二、三级分类)显示

在 list/list.vue 引入list/listNav.vue 组件


通过导航点击进入,此时链接为: http://127.0.0.1:8080/#/app/home/list/121

image.png

通过搜索进入,此时链接为: http://127.0.0.1:8080/#/app/home/search/%E7%89%9B%E8%82%89

image.png

跳转不同页面显示面包屑

获取当前点击分类的id,然后根据这个分类获取父级分类的详情。

父级分类序列化器ParentCategorySerializer

修改 goods/serializers.py ,添加序列化类

# 获取父级分类
class ParentCategorySerializer3(serializers.ModelSerializer):
    class Meta:
        model = GoodsCategory
        fields = '__all__'


class ParentCategorySerializer2(serializers.ModelSerializer):
    parent_category = ParentCategorySerializer3()

    class Meta:
        model = GoodsCategory
        fields = '__all__'


class ParentCategorySerializer(serializers.ModelSerializer):
    parent_category = ParentCategorySerializer2()

    class Meta:
        model = GoodsCategory
        fields = '__all__'

父级分类视图ParentCategoryViewSet

修改 goods/views.py 增加视图

class ParentCategoryViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    """
    list:
        根据子类别查询父类别
    """
    queryset = GoodsCategory.objects.all()
    serializer_class = ParentCategorySerializer

父级分类URL

修改主 urls.py 注册父级分类的url

# 创建一个路由器并注册我们的视图集
router = DefaultRouter()
router.register(r'goods', GoodsListViewSet, base_name='goods')  # 配置goods的url
router.register(r'categories', CategoryViewSet, base_name='categories')  # 配置分类的url
router.register(r'parent_categories', ParentCategoryViewSet, base_name='parent_categories')  # 配置分类的url

比如获取分类“牛肉”的父级分类,只需要请求该API: http://127.0.0.1:8000/parent_categories/126/

image.png

获取当前请求位置getCurLoc(id)

该函数用于提供点击的分类id:this.getCurLoc(curloc_id); // 获取当前位置,请求后组合分类面包屑。

list/list.vue

//获取当前位置
getCurLoc(id) { // 当前位置
    getParentCategory({
        id: id  //传递指定分类的id
    }).then((response) => {
        console.log('list/list.vue 获取当前位置:');
        console.log(response.data);
        var dt = response.data;
        var curLoc;
        //组合类别
        var index_p = {'id': 0, 'name': '首页'};
        var first = {'id': dt.id, 'name': dt.name};
        curLoc = [index_p, first];
        if (dt.parent_category != null) {
            var second = {'id': dt.parent_category.id, 'name': dt.parent_category.name};
            curLoc = [index_p, second, first];
            if (dt.parent_category.parent_category != null) {
                var third = {'id': dt.parent_category.parent_category.id, 'name': dt.parent_category.parent_category.name};
                curLoc = [index_p, third, second, first];
            }
        }
        this.curLoc = curLoc
    }).catch(function (error) {
        console.log(error);
    });
},
image.png

显示价格区间组件getPriceRange()

将 list/list.vue 中的数据填充到 list/price-range/priceRange.vue 中

getPriceRange() {
    //价格区间显示,不使用上方mock.js中的内容
    this.priceRange = [
        {
            min: 1,
            max: 30,
        },
        {
            min: 31,
            max: 80,
        },
        {
            min: 81,
            max: 150,
        },
        {
            min: 151,
            max: 300,
        },
    ]
},


changePrice(data) {
    this.pricemin = data.min;
    this.pricemax = data.max;
    this.getListData();
},

数据显示到 priceRange.vue


image.png

商品排序

changeSort(type) {
    this.ordering = type;
    this.getListData();
},

数据显示到 list/list-sort/listSort.vue

{{proNum}}个商品
image.png

商品列表分页

修改分页参数

将goods列表分页参数p修改为page,修改 goods/views.py 中的GoodsPagination类,且每一页显示12个数据

class GoodsPagination(PageNumberPagination):
    page_size = 12  # 每一页个数,由于前段
    page_size_query_param = 'page_size'
    page_query_param = 'page'  # 参数?p=xx,将其修改为page,适应前端,也方便识别
    max_page_size = 36  # 最大指定每页个数

商品分页

list/list.vue

pagefn(value) {//点击分页
    this.curPage = value.page;
    this.getListData()
}

传递分页值到

image.png

获取商品列表

自定义过滤分类top_category_filter

用于过滤某个分类下的所有商品。例如获取一级分类下的所有商品,就需要同时获取二三级分类的商品。

自定义过滤,按照分类的进行过滤商品,修改 goods/filters.py 中商品过滤类GoodsFilter

class GoodsFilter(filters.FilterSet):
    """
    商品的过滤类
    """
    name = filters.CharFilter(field_name='name', lookup_expr='contains')  # 包含关系,模糊匹配
    goods_desc = filters.CharFilter(field_name='name', lookup_expr='contains')
    min_price = filters.NumberFilter(field_name="shop_price", lookup_expr='gte')  # 自定义字段
    max_price = filters.NumberFilter(field_name="shop_price", lookup_expr='lte')
    top_category = filters.NumberFilter(method='top_category_filter', field_name='category_id', lookup_expr='=')  # 自定义过滤,过滤某个一级分类

    def top_category_filter(self, queryset, field_name, value):
        """
        自定义过滤内容
        这儿是传递一个分类的id,在已有商品查询集基础上获取分类id,一级一级往上找,直到将三级类别找完
        :param queryset:
        :param field_name:
        :param value: 需要过滤的值
        :return:
        """
        queryset = queryset.filter(Q(category_id=value) | Q(category__parent_category_id=value) | Q(category__parent_category__parent_category_id=value))
        return queryset

    class Meta:
        model = Goods
        fields = ['name', 'goods_desc', 'min_price', 'max_price']

不管是点击一级分类、二级分类、三级分类,都能被找到。

image.png

这个函数的意思就是对已经过滤后的查询集,进行分类id过滤,比如

>>> from goods.models import Goods
>>> from django.db.models import Q
>>> all_goods = Goods.objects.all()
>>> all_goods1 = all_goods.filter(shop_price__gte=150)
>>> all_goods1  # 获取到价格高于150的所有商品
, , , , , , , ]>
>>> all_goods1.filter(category_id=122)  # 这是个二级分类
]>
>>> all_goods1.filter(category__parent_category_id=122)

>>> all_goods1.filter(Q(category_id=122)|Q(category__parent_category_id=122))
]>

在所有级别的分类id中进行查找,并获取所有的商品。

获取商品列表getListData()

//获取商品列表
getListData() {
    console.log('list/list.vue 获取商品获取方式(list列出、search搜索):' + this.pageType);

    if (this.pageType === 'search') {
        getGoods({
            search: this.searchWord, //搜索关键词
            top_category: this.top_category, //商品类型,一级类别的id
            ordering: this.ordering, //排序类型
            min_price: this.pricemin, //价格最低 默认为‘’ 即为不选价格区间
            max_price: this.pricemax // 价格最高 默认为‘’
        }).then((response) => {
            this.listData = response.data.results;
            console.log('list/list.vue 获取商品列表:');
            console.log(response.data);
            this.proNum = response.data.count;
        }).catch(function (error) {
            console.log(error);
        });
    } else {
        getGoods({
            //以下是url中的过滤参数
            page: this.curPage, //当前页码
            top_category: this.top_category, //商品类型,一级类别的id
            ordering: this.ordering, //排序类型
            min_price: this.pricemin, //价格最低 默认为‘’ 即为不选价格区间
            max_price: this.pricemax // 价格最高 默认为‘’
        }).then((response) => {

            this.listData = response.data.results;
            console.log('list/list.vue 获取商品列表:');
            console.log(response.data);
            this.proNum = response.data.count;
        }).catch(function (error) {
            console.log(error);
        });
    }
},

list/list.vue 中将数据通过 显示到 list/productList.vue

  • ¥{{item.shop_price}}元 {{item.name}} {{item.goods_brief}} 销量:{{item.sold_num}}

image.png

你可能感兴趣的:(【Vue+DRF生鲜电商】11.Vue展示左侧分类、面包屑、排序、商品列表、分页)