Django+Vue开发生鲜电商平台之6.使用Vue实现商品类别和商品数据前台显示(下)

简介: 由之前的效果图和需求分析可知,首页全部商品分类需要展示一级、二级和三级分类,而在搜索结果页只展示一级和二级分类,分类有两个Vue组件,即Header中的全部商品分类和左侧的某以及类别对应的分类导航栏,也对应两个数据接口。

为了让数据在前端正常显示,还需要过滤类别数据、只显示一级类别,修改views.py如下:

class CategoryViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    '''
    List: 显示商品所有分类列表数据
    Retrieve: 获取单个商品分类详情
    '''
    queryset = GoodsCategory.objects.filter(category_type=1)
    serializer_class = CategorySerializer

此时再访问http://127.0.0.1:8080,显示:

image.jpeg

此时再访问,却访问不到商品分类,查看控制台提示很明显,同源策略禁止读取位于 http://127.0.0.1:8000/categorys/ 的远程资源。,即禁止跨域访问,当前端口是 8080,而数据接口端口是8000,因此被浏览器自动拒绝,一种方式是对服务器进行设置,还有一种是通过前端代理解决,这里采用第一种方式:

首先在虚拟环境中执行pip install django-cors-headers命令安装库,然后在后端settings.py中配置Cors:

INSTALLED_APPS = [
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'apps.users.apps.UsersConfig',
    'goods.apps.GoodsConfig',
    'trade.apps.TradeConfig',
    'user_operation.apps.UserOperationConfig',
    'DjangoUeditor',
    'xadmin',
    'crispy_forms',
    'django.contrib.admin',
    'rest_framework',
    'django_filters',
    'corsheaders',
]
MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
# 跨域访问设置
CORS_ORIGIN_ALLOW_ALL = True

此时再访问,显示:

image.jpeg

此时不再报错,商品的各级分类也显示出来,但是可以看出来,全部分类右侧并未显示商品分类,这是因为一级分类的is_tab属性默认为False,改为True即可,可以在数据库中修改,也可以直接在后台管理系统修改。

head.vue中显示商品分类的逻辑也是通过循环实现,如下:

<template v-for="(item,index) in allMenuLabel">
    <li>
        <div v-if="item.is_tab">
            <router-link :to="'/app/home/list/'+item.id" >{{item.name}}</router-link>
        </div>
    </li>
</template>

后台修改商品分类is_tab属性并刷新页面如下:


image.jpeg


此时已经显示出商品分类。

三、Vue展示商品列表页数据和搜索

现在进一步实现点击某一个商品分类下面显示出商品详情,具体包括分类显示、价格筛选、分页和排序等功能。

通过项目可以看到,通过搜索和点击Tab页左侧显示的导航栏是不同的,其数据接口也不一样,head.vue如下:

<div class="head_search_hot">
  <span>热搜榜:</span>
  <router-link v-for="item in hotSearch" :to="'/app/home/search/'+item.keywords" :key="item.keywords">
    {{item.keywords}}
  </router-link>
</div>
// ...
<div class="main_nav_link" @mouseover="overAllmenu" @mouseout="outAllmenu">
    <a class="meunAll">全部商品分类
        <i class="iconfont">&#xe643;</i>
    </a>
    <div class="main_cata" id="J_mainCata" v-show="showAllmenu">
        <ul>
            <li class="first" v-for="(item,index) in allMenuLabel" @mouseover="overChildrenmenu(index)" @mouseout="outChildrenmenu(index)">
              <h3 style="background:url(../images/1449088788518670880.png) 20px center no-repeat;">
                <router-link :to="'/app/home/list/'+item.id">{{item.name}}</router-link> </h3>
                <div class="J_subCata" id="J_subCata" v-show="showChildrenMenu ===index"  style=" left: 215px; top: 0px;">
                    <div class="J_subView" >
                      <div v-for="list in item.sub_cat">
                        <dl>
                          <dt>
                            <router-link :to="'/app/home/list/'+list.id">{{list.name}}</router-link>
                          </dt>
                          <dd>
                            <router-link  v-for="childrenList in list.sub_cat" :key="childrenList.id" :to="'/app/home/list/'+childrenList.id">{{childrenList.name}}</router-link>
                          </dd>
                        </dl>
                        <div class="clear"></div>
                      </div>
                    </div>
                </div>
            </li>
        </ul>
    </div>
</div>

可以看到,跳转路由不同,搜索跳转到/app/home/search/,而点击导航栏跳转到/app/home/list/


再查看src/router/index.js如下:

{
  path: 'list/:id',
  name: 'list',
  component: list,
  meta: {
    title: '列表',
    need_log: false
  }
},
{
  path: 'search/:keyword',
  name: 'search',
  component: list,
  meta: {
    title: '搜索',
    need_log: false
  }
},

可以看到,两个路由绑定的组件是相同的,都是list,而在src/views/list/list.vue中:

getAllData () {
    console.log(this.$route.params)
    if(this.$route.params.id){
        this.top_category = this.$route.params.id;
        this.getMenu(this.top_category); // 获取左侧菜单列表
    }else{
        this.getMenu(null); // 获取左侧菜单列表
        this.pageType = 'search'
        this.searchWord = this.$route.params.keyword;
    }
    this.getCurLoc(); // 获取当前位置
    this.getListData(); //获取产品列表
    this.getPriceRange(); // 获取价格区间
},
getListData() {
    if(this.pageType=='search'){
      getGoods({
        search: this.searchWord, //搜索关键词
      }).then((response)=> {
        this.listData = response.data.results;
        this.proNum = response.data.count;
      }).catch(function (error) {
        console.log(error);
      });
    }else {
      getGoods({
        page: this.curPage, //当前页码
        top_category: this.top_category, //商品类型
        ordering: this.ordering, //排序类型
        pricemin: this.pricemin, //价格最低 默认为‘’ 即为不选价格区间
        pricemax: this.pricemax // 价格最高 默认为‘’
      }).then((response)=> {
        this.listData = response.data.results;
        this.proNum = response.data.count;
      }).catch(function (error) {
        console.log(error);
      });
    }
},
getMenu(id) {
    if(id != null){
      getCategory({
        id:this.$route.params.id
      }).then((response)=> {
        this.cateMenu = response.data.sub_cat;
        this.currentCategoryName = response.data.name
      }).catch(function (error) {
        console.log(error);
      });
    }else {
      getCategory({}).then((response)=> {
        this.cateMenu = response.data;
        this.isObject = false
      }).catch(function (error) {
        console.log(error);
      });
    }
},

可以看到,针对不同的参数有不同的请求方法和参数。


请求商品列表数据使用的是getListData()方法,调用了getGoods()方法,为了测试获取商品,将getGoodsAPI进行修改如下:

//获取商品列表
export const getGoods = params => { return axios.get(`${local_host}/goods/`, { params: params }) }

同时,向后端请求的参数有一个为top_category,即表示一级类别,请求该参数则返回这一类别下的所有类别,需要在后端定义一个过滤器,需要找到该一级分类下的所有二级分及其对应的商品,后端apps/goods/filters.py如下:

import django_filters
from django.db.models import Q
from .models import Goods
class GoodsFilter(django_filters.rest_framework.FilterSet):
    '''商品过滤类'''
    name = django_filters.CharFilter(field_name="name", lookup_expr='contains')
    pricemin = django_filters.NumberFilter(field_name="market_price", lookup_expr='gte')
    pricemax = django_filters.NumberFilter(field_name="market_price", lookup_expr='lte')
    top_category = django_filters.NumberFilter(method='top_category_filter')
    def top_category_filter(self, queryset, name, value):
        '''自定义过滤'''
        return queryset.filter(Q(category_id=value)|Q(category__parent_category_id=value)|Q(category__parent_category__parent_category_id=value))
    class Meta:
        model = Goods
        fields = ['name', 'pricemin', 'pricemax']

显示:

image.jpeg


此时,可以根据top_category进行筛选,再查看前端:


image.jpeg


可以看到,已经实现了价格筛选、排序、分页等功能。


从之前的代码还可以看到搜索功能的实现:

if(this.pageType=='search'){
  getGoods({
    search: this.searchWord, //搜索关键词
  }).then((response)=> {
    this.listData = response.data.results;
    this.proNum = response.data.count;
  }).catch(function (error) {
    console.log(error);
  });
}

再测试搜索功能如下:


2345_image_file_copy_28.jpg


显然,已经实现了搜索功能。

相关文章
|
22天前
|
JavaScript 前端开发 开发者
哇塞!Vue.js 与 Web Components 携手,掀起前端组件复用风暴,震撼你的开发世界!
【8月更文挑战第30天】这段内容介绍了Vue.js和Web Components在前端开发中的优势及二者结合的可能性。Vue.js提供高效简洁的组件化开发,单个组件包含模板、脚本和样式,方便构建复杂用户界面。Web Components作为新兴技术标准,利用自定义元素、Shadow DOM等技术创建封装性强的自定义HTML元素,实现跨框架复用。结合二者,不仅增强了Web Components的逻辑和交互功能,还实现了Vue.js组件在不同框架中的复用,提高了开发效率和可维护性。未来前端开发中,这种结合将大有可为。
65 0
|
9天前
|
JavaScript
vue学习(8)数据代理
vue学习(8)数据代理
21 1
|
1月前
|
JavaScript
Vue学习之--------深入理解Vuex之多组件共享数据(2022/9/4)
这篇文章通过一个实际的Vue项目案例,演示了如何在Vuex中实现多组件间共享数据。文章内容包括在Vuex的state中新增用户数组,创建Person.vue组件用于展示和添加用户信息,以及在Count组件中使用Person组件操作的数据。通过测试效果展示了组件间数据共享和状态更新的流程。
Vue学习之--------深入理解Vuex之多组件共享数据(2022/9/4)
|
1月前
|
数据采集 自然语言处理 监控
【优秀python毕设案例】基于python django的新媒体网络舆情数据爬取与分析
本文介绍了一个基于Python Django框架开发的新媒体网络舆情数据爬取与分析系统,该系统利用Scrapy框架抓取微博热搜数据,通过SnowNLP进行情感分析,jieba库进行中文分词处理,并以图表和词云图等形式进行数据可视化展示,以实现对微博热点话题的舆情监控和分析。
【优秀python毕设案例】基于python django的新媒体网络舆情数据爬取与分析
|
30天前
|
JavaScript 前端开发
vue全局公共组件自动引入并注册,开发效率直接起飞!
【8月更文挑战第17天】vue全局公共组件自动引入并注册,开发效率直接起飞!
32 3
|
7天前
|
JavaScript
Vue组件传值异步问题--子组件拿到数据较慢
Vue组件传值异步问题--子组件拿到数据较慢
11 0
|
30天前
|
设计模式 JavaScript 前端开发
Vue.js 组件设计模式:在前端热潮中找到归属感,打造可复用组件库,开启高效开发之旅!
【8月更文挑战第22天】Vue.js 以其高效构建单页应用著称,更可通过精良的组件设计打造可复用组件库。组件应职责单一、边界清晰,如一个显示文本并触发事件的按钮组件,通过 props 传递标签文本,利用插槽增强灵活性,允许父组件注入动态内容。结合 CSS 预处理器管理和封装独立模块,配以详尽文档,有效提升开发效率及代码可维护性。合理设计模式下,组件库既灵活又强大,持续实践可优化项目工作流。
40 1
|
1月前
|
JavaScript 前端开发
Vue学习之--------Vue中收集表单数据(使用v-model 实现双向数据绑定、代码实现)(2022/7/18)
这篇文章介绍了Vue中使用v-model实现表单数据收集的方法,包括基础知识、代码实例和测试效果,并提供了一些额外建议。
Vue学习之--------Vue中收集表单数据(使用v-model 实现双向数据绑定、代码实现)(2022/7/18)
|
1月前
|
JavaScript API
Vue学习之--------列表排序(ffilter、sort、indexOf方法的使用)、Vue检测数据变化的原理(2022/7/15)
这篇博客文章讲解了Vue中列表排序的方法,使用`filter`、`sort`和`indexOf`等数组方法进行数据的过滤和排序,并探讨了Vue检测数据变化的原理,包括Vue如何通过setter和数组方法来实现数据的响应式更新。
Vue学习之--------列表排序(ffilter、sort、indexOf方法的使用)、Vue检测数据变化的原理(2022/7/15)
|
1月前
|
JavaScript
Element - Vue使用slot-scope和v-for遍历数据为树形表格
这篇文章介绍了在Vue中使用`slot-scope`和`v-for`指令来遍历数据并将其渲染为树形表格的方法。
25 0
Element - Vue使用slot-scope和v-for遍历数据为树形表格