欢迎访问我的博客专题
源码可访问 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
通过搜索进入,此时链接为: http://127.0.0.1:8080/#/app/home/search/%E7%89%9B%E8%82%89
跳转不同页面显示面包屑
获取当前点击分类的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/
获取当前请求位置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);
});
},
显示价格区间组件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
商品排序
changeSort(type) {
this.ordering = type;
this.getListData();
},
数据显示到 list/list-sort/listSort.vue
共{{proNum}}个商品
商品列表分页
修改分页参数
将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()
}
传递分页值到
获取商品列表
自定义过滤分类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']
不管是点击一级分类、二级分类、三级分类,都能被找到。
这个函数的意思就是对已经过滤后的查询集,进行分类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}}件