前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >猿实战18——商品发布之类目选择

猿实战18——商品发布之类目选择

作者头像
山旮旯的胖子
发布2020-09-28 09:44:17
6490
发布2020-09-28 09:44:17
举报
文章被收录于专栏:猿人工厂

猿实战是一个原创系列文章,通过实战的方式,采用前后端分离的技术结合SpringMVC Spring Mybatis,手把手教你撸一个完整的电商系统,变身猿人找到工作不是问题。还等什么呢?关注公号,取基础代码,一起实战吧。

经过之前一些列章节的实战,我们终于离我们的目标系统越来越接近了,从今天开始到接下来的六个章节,我们一起来重点关注商品的那点儿事儿,今天我们先重点讲解商品发布时的类目选择功能。

功能概览

在商品发布的功能中,商品发布有三个步骤,选择类目,填写信息,提交信息。

今天我们要讲到的选择类目功能,其实和之前讲的类目联动选择并没有很大的区别,只是我们在选择的展示上已经数据的获取方式上有细微差别。

类目选择依然是保持了三级联动的方式进行,用户必须选择完整的三级类目才可以发布商品信息。

数据库设计

发布商品时,使用的是后台类目,后台类目的数据库设计之前已经有了,这里就不一一讲解了。

后端功能实现

在之前的过程中,我们灵活使用了带分页的类目查询来实现类目的下拉选择,其实这样做只是一个狗皮膏药而已,正确的做法是,每一级都需要查出所有的数据,之前之所以那样去处理,目的是告诉你问题的灵活解决之道。

废话不多讲了,我们先来看看后端数据功能是怎样实现的。

代码语言:javascript
复制
/**
     * 不分页返回类目列表
     * @param queryMallCategory
     * @return
     */
    @RequestMapping("/findByQuery")
    public  Result<List<MallCategory>> findByQuery(@RequestBody QueryMallCategory queryMallCategory){
        return mallCategoryService.getMallCategorysByQuery(queryMallCategory);
    }

由于service层和dao层是透传的,我们主要看下mapper层的区别。

通过mysql数据库做分页查询的本质在于使用limit关键字,第一个参数告知数据库从第几行取,第二个参数告知数据库取多少条记录。

前端功能实现

前端功能的实现,主要还是基于element-ui来实现的。这里主要使用的是el-cascader-panel组件。el-cascader-panel被称作联级选择器。最广泛和深入的用法,大家可以访问官网进行学习。

https://element.eleme.cn/2.0/#/zh-CN/component/cascader

我们先重点关注,需要掌握的核心知识。

选择类目时的联级选择器的使用很简单代码如下:

代码语言:javascript
复制
<el-cascader-panel ref="cascaderCategory" v-model="cascaderValue" :options="options" :props="props" @change="change" @active-item-change="handleItemChange" />

ref:定义了用于引用访问的组件的id.

v-model:数据源。

options:可选项数据源,键名可通过 props 属性配置。

props:配置项目,具体见下表。

change:当绑定值变化时触发的事件。

active-item-change:当父级选项变化时触发的事件,仅在 change-on-select 为 false 时可用。

在选择每一级类目时,我们需要记录已经选择的类目,所以我们需要为change事件绑定函数。

注意噢,类目名称很重要,不光仅仅时展示噢,怎么获取呢?这就需要你对数据组件的数据结构有一定掌握了。其实,我们在接触一个组件时,对这些并不熟悉,有一个简易的办法就是使用console.log取查看。

数据联动的事件处理,大家可以先看一下:

注意,只有当选择了具体的类目时,才会去动态出发数据加载的功能。在选择类目时,还需要区分选择的类目层级,如果是二级则需要给下一句创建一个空的数组,否则选择了二级类目不会触发三级类目的数据加载函数。

知道你不是很熟悉前端,而这部分工作,对你来说是一个长期而又漫长的过程,这里把前端代码给到你。

代码语言:javascript
复制
<template>
  <div id="goodsReleasedDiv">
    <el-container>
      <el-card shadow="never">
        <div>
          <span style="font-weight: 700;">发布商品</span>
          <div style="float:right;padding-right:20px;font-size: 15px;">
            <a style="color:#4395ff">1.选择类目</a>
            -> 2.填写详细信息
            -> 3.提交信息</div>
        </div>
        <div style="padding-left:20px;padding-right:20px;">
          <div style="margin-top:20px;margin-bottom:20px;">选择您要使用的类目:
          </div>
          <el-cascader-panel ref="cascaderCategory" v-model="cascaderValue" :options="options" :props="props" @change="change" @active-item-change="handleItemChange" />
          <div>
            您当前选择的类目是:<span v-if="oneCategory">{{ oneCategory }} > {{ twoCategory }} > {{ threeCategory }} </span>
          </div>
          <div style="text-align: center;margin-top:20px;">
            <el-button type="primary" @click="addClick">
              我已阅读以下规则,现在发布商品
            </el-button>
          </div>
        </div>
      </el-card>
    </el-container>
  </div>
</template>
 
<script>
import { fetchCategoryListNoPage } from '@/api/product-manage'
export default {
  data() {
    return {
      props: {
        label: 'categoryName',
        value: 'categoryId',
        children: 'child'
      },
      oneCategory: '',
      twoCategory: '',
      threeCategory: '',
      oneCategoryId: 0,
      twoCategoryId: 0,
      threeCategoryId: 0,
      cascaderValue: [],
      options: [],
      category: '',
      listQuery: {
        // 类目属性
        page: 1,
        pageSize: 20,
        level: 1
      }
    }
  },
  created() {
    this.getFristCategoryList()
  },
  methods: {
    // 商品发布按钮
    addClick() {
      this.$router.push({
        path: '/shops/goods-released-detail',
        query: { oneCategory: this.oneCategory, twoCategory: this.twoCategory,
          threeCategory: this.threeCategory, oneCategoryId: this.oneCategoryId,
          twoCategoryId: this.twoCategoryId, threeCategoryId: this.threeCategoryId }
      })
    },
    change(value) {
      console.log(this.$refs.cascaderCategory.getCheckedNodes()[0].pathLabels)
      if (value[0]) {
        this.oneCategory = this.$refs.cascaderCategory.getCheckedNodes()[0].pathLabels[0]
        this.oneCategoryId = value[0]
      }
      if (value[1]) {
        this.twoCategory = this.$refs.cascaderCategory.getCheckedNodes()[0].pathLabels[1]
        this.twoCategoryId = value[1]
      }
      if (value[2]) {
        this.threeCategory = this.$refs.cascaderCategory.getCheckedNodes()[0].pathLabels[2]
        this.threeCategoryId = value[2]
      }
      console.log(value)
    },
    getFristCategoryList() {
      fetchCategoryListNoPage(this.listQuery).then(response => {
        this.options = response.model
        this.options.map((item, index, array) => {
          // 因为数组和对象更新后不会更新视图,这里必须用$set方法
          this.$set(array[index], 'child', [])
        })
      })
    },
    handleItemChange(value) {
      // 动态/异步加载分类数据
      let parentId
      if (value.length === 1) {
        // 如果点击的是一级分类
        parentId = value[0]
        this.options.map((item, index) => {
          if (item.categoryId === parentId && item.child.length === 0) {
            this.listQuery.parentId = parentId
            this.listQuery.level = 2
            fetchCategoryListNoPage(this.listQuery).then(response => {
              this.$set(this.options[index], 'child', response.model)
              item.child.map((innerItem, innerIndex) => {
                // 二级分类下必须要设置一个空的child数组,不然点击@active-item-change没反应
                this.$set(item.child[innerIndex], 'child', [])
              })
            })
          }
        })
      } else {
        // 如果点击的是二级分类,则直接将三级分类绑定到platOptions
        parentId = value[1]
        console.log(parentId)
        this.options.map((item, index) => {
          if (item !== null) {
            item.child.map((innerItem, innerIndex) => {
              if (innerItem.categoryId === parentId && innerItem.child.length === 0) {
                this.listQuery.parentId = parentId
                this.listQuery.level = 3
                // 当二级分类的的child不为空时才请求一次数据
                fetchCategoryListNoPage(this.listQuery).then(response => {
                  this.$set(item.child[innerIndex], 'child', response.model)
                })
              }
            })
          }
        })
      }
    }
  }
}
</script>
 
<style scoped>
#goodsReleasedDiv .form-container {
    width: 1200px;
    margin: 0 auto;
    min-height: 770px;
  }
 #goodsReleasedDiv /deep/ .el-card__body {
    padding: 0px 0px 20px 0px ;
 }
  #goodsReleasedDiv .issueDiv {
    font-size: 18px;
    line-height: 18px;
    padding-top: 10px;
    padding-bottom: 10px;
    padding-left: 20px;
    background: #f9f9f9;;
  }
  #goodsReleasedDiv /deep/ .el-cascader-menu__wrap {
    height: 400px;
  }
  #goodsReleasedDiv .el-cascader-panel.is-bordered {
    height: 400px;
  }
  #goodsReleasedDiv .categoryDiv {
    padding-top: 10px;
    border: solid 1px #dfe4ed;
    border-radius: 4px;
    padding-bottom: 10px;
    margin-top: 20px;
    padding-left: 20px;
  }
</style>
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-09-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 猿人工厂 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档