基于vue写的自定义商品三级分类,包括搜索分类全是前端控制

概述

一款基于vue所写的商品三级分类,包括搜所全是前端的控制,这里的搜索用到递归写法供大家参考

详细

1,项目结构

image.png

2,截图

image.png

3,html部分

 <div style="width: 100%; display: flex">
    <div class="right-info-box">
      <div class="warp_group">
        <div class="group_card">
          <el-autocomplete v-model="search" 
            :trigger-on-focus="false" 
            :fetch-suggestions="querySearchAsync" 
            placeholder="请输入内容" 
            @select="handleSelect">
            <el-button slot="append" icon="el-icon-search" @click="getSearch" />
          </el-autocomplete>
        </div>
        <div class="line_box">
          <div class="group_flex">
            <div class="group_item">
              <span class="h_text">一级分类</span>
              <div class="btn">
                <el-button size="small" icon="el-icon-plus" class="el-button wfu-btn-add">新增一级分类</el-button>
              </div>
            </div>
            <div class="group_content_box">
              <div class="group_content_title">
                <span>分类名称</span>
                <span
                  >排序
                  <el-popover content="序号越大,排序越靠前" placement="top" trigger="hover" width="180">
                    <i slot="reference" style="color: #bbbfc8" class="el-icon-warning" />
                  </el-popover>
                </span>
                <span>操作</span>
              </div>
              <el-scrollbar style="height: 572px">
                <div v-loading="loading" class="item_attr" @click="tabClass('1',index)"  :class="{avtive:num === index}" v-for="(item,index) in first" :key="index">
                  <div class="item_name_box">
                    <img
                      class="img"
                      :src="item.picture"
                      alt=""
                    />
                    <span class="item_name_title">{{item.title}}</span>
                  </div>
                  <div class="item_sort">
                    {{item.weight}}
                    <el-popover trigger="click">
                      <div class="sort_box">
                        <el-input v-model.number="sort" size="small" />
                        <div class="sort_btn">
                          <el-button size="mini" type="text">取消 </el-button>
                          <el-button size="mini" type="primary">确定 </el-button>
                        </div>
                      </div>
                      <span slot="reference" @click="editSort(item)">
                        <i class="el-icon-edit showIcon" />
                      </span>
                    </el-popover>
                  </div>
                  <div class="item_handle">
                    <el-popover placement="top-start" width="50" trigger="hover" content="编辑">
                      <span slot="reference" class="handel_icon">
                        <i class="el-icon-edit" />
                      </span>
                    </el-popover>
                    <el-popover placement="top-start" width="50" trigger="hover" content="隐藏">
                      <span slot="reference" class="handel_icon">
                        <i class="iconfont icon-yincang" />
                      </span>
                    </el-popover>
                    <el-popover placement="top-start" width="50" trigger="hover" content="删除">
                      <span slot="reference" class="handel_icon">
                        <i class="el-icon-delete" />
                      </span>
                    </el-popover>
                  </div>
                </div>
              </el-scrollbar>
            </div>
          </div>
          <div class="group_flex">
            <div class="group_item">
              <span class="h_text">二级分类</span>
              <div class="btn">
                <el-button size="small" icon="el-icon-plus" class="el-button wfu-btn-add">新增二级分类</el-button>
              </div>
            </div>
            <div class="group_content_box">
              <div class="group_content_title">
                <span>分类名称</span>
                <span
                  >排序
                  <el-popover content="序号越大,排序越靠前" placement="top" trigger="hover" width="180">
                    <i slot="reference" style="color: #bbbfc8" class="el-icon-warning" />
                  </el-popover>
                </span>
                <span>操作</span>
              </div>
              <el-scrollbar style="height: 572px">
                <div v-loading="loading" class="item_attr" :class="{avtive:sum === index}" @click="tabClass('2',index)" v-for="(item,index) in second" :key="index">
                  <div class="item_name_box">
                    <img
                      class="img"
                      :src="item.picture"
                      alt=""
                    />
                    <span class="item_name_title">{{item.title}}</span>
                  </div>
                  <div class="item_sort">
                    {{item.weight}}
                    <el-popover trigger="click">
                      <div class="sort_box">
                        <el-input v-model.number="sort" size="small" />
                        <div class="sort_btn">
                          <el-button size="mini" type="text">取消 </el-button>
                          <el-button size="mini" type="primary">确定 </el-button>
                        </div>
                      </div>
                      <span slot="reference" @click="editSort(item)">
                        <i class="el-icon-edit showIcon" />
                      </span>
                    </el-popover>
                  </div>
                  <div class="item_handle">
                    <el-popover placement="top-start" width="50" trigger="hover" content="编辑">
                      <span slot="reference" class="handel_icon">
                        <i class="el-icon-edit" />
                      </span>
                    </el-popover>
                    <el-popover placement="top-start" width="50" trigger="hover" content="隐藏">
                      <span slot="reference" class="handel_icon">
                        <i class="iconfont icon-yincang" />
                      </span>
                    </el-popover>
                    <el-popover placement="top-start" width="50" trigger="hover" content="删除">
                      <span slot="reference" class="handel_icon">
                        <i class="el-icon-delete" />
                      </span>
                    </el-popover>
                  </div>
                </div>
              </el-scrollbar>
            </div>
          </div>
          <div class="group_flex">
            <div class="group_item">
              <span class="h_text">三级分类</span>
              <div class="btn">
                <el-button size="small" icon="el-icon-plus" class="el-button wfu-btn-add">新增三级分类</el-button>
              </div>
            </div>
            <div class="group_content_box">
              <div class="group_content_title">
                <span>分类名称</span>
                <span
                  >排序
                  <el-popover content="序号越大,排序越靠前" placement="top" trigger="hover" width="180">
                    <i slot="reference" style="color: #bbbfc8" class="el-icon-warning" />
                  </el-popover>
                </span>
                <span>操作</span>
              </div>
              <el-scrollbar style="height: 572px">
                <div v-loading="loading" class="item_attr" v-for="(item,index) in tertiary" :key="index">
                  <div class="item_name_box">
                    <img
                      class="img"
                      :src="item.picture"
                      alt=""
                    />
                    <span class="item_name_title">{{item.title}}</span>
                  </div>
                  <div class="item_sort">
                    {{item.weight}}
                    <el-popover trigger="click">
                      <div class="sort_box">
                        <el-input v-model.number="sort" size="small" />
                        <div class="sort_btn">
                          <el-button size="mini" type="text">取消 </el-button>
                          <el-button size="mini" type="primary">确定 </el-button>
                        </div>
                      </div>
                      <span slot="reference" @click="editSort(item)">
                        <i class="el-icon-edit showIcon" />
                      </span>
                    </el-popover>
                  </div>
                  <div class="item_handle">
                    <el-popover placement="top-start" width="50" trigger="hover" content="编辑">
                      <span slot="reference" class="handel_icon">
                        <i class="el-icon-edit" />
                      </span>
                    </el-popover>
                    <el-popover placement="top-start" width="50" trigger="hover" content="隐藏">
                      <span slot="reference" class="handel_icon">
                        <i class="iconfont icon-yincang" />
                      </span>
                    </el-popover>
                    <el-popover placement="top-start" width="50" trigger="hover" content="删除">
                      <span slot="reference" class="handel_icon">
                        <i class="el-icon-delete" />
                      </span>
                    </el-popover>
                  </div>
                </div>
              </el-scrollbar>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>

4,搜索部分

<script>
export default {
  data() {
    return {
      search: "", //搜索分类
      restaurants: [], //搜索列表
      superList:[], //搜索列表
      arrList:[], //搜索列表
      searchChoose:null, //搜索框搜索对象
      sort: "", //修改排序
      // first:[],
      first: [
        {
          companyId: "1459065453856628738",
          id: "1498220618477977601",
          itemCategoryVOList: [
            {
              id: "1527485176463355905",
              itemCategoryVOList:[
                {
                  id: "1527485531259531266",
                  lastFlag: 1,
                  level: 3,
                  picture: "https://zk-micro.oss-cn-hangzhou.aliyuncs.com/595c56e961efd3d737b6df6736740c8c.jpeg",
                  previous: "1527485176463355905",
                  title: "测试",
                  weight: 1
                }
              ],
              lastFlag: 0,
              level: 2,
              picture: "https://zk-micro.oss-cn-hangzhou.aliyuncs.com/a0db1ab50f8a604fc56bc231b92ec7b5.jpeg",
              previous: "1498220618477977601",
              title: "测试",
              weight: 1
            }
          ],
          level: 1,
          picture: "https://zk-micro.oss-cn-hangzhou.aliyuncs.com/tomas-malik-q4aPGKEq0pM-unsplash.jpg",
          previous: "0",
          title: "医疗保健",
          weight: 34
        }
      ], //一级分类列表
      second:[], //二级分类列表
      tertiary:[], //三级分类列表
      num:0, //二级分类
      sum:0, //三级分类
      loading:false
    };
  },
  created() {},
  mounted() {
    this.getList()
  },
  methods: {
    // 分类列表
    getList() { //接口方法
      // this.loading = true
      // this.$api.amys.shopGroup.list().then(res => {
      //   if (res.data && res.status == "00000") {
      //     this.arrList = this.resFormat(res.data) //搜索一级分类
      //     this.superList = this.arrList //分类列表
      //     this.loading = false
      //     this.restaurants = []; //搜索框列表
      //     this.listType() //tab切换
      //     this.searchList(res.data)//搜素框递归查找分类
      //   } else {
      //     this.$message.error(res.message);
      //   }
      // });
       this.arrList = this.resFormat(this.first) //搜索一级分类
          this.superList = this.arrList //分类列表
          this.loading = false
          this.restaurants = []; //搜索框列表
          this.listType() //tab切换
          this.searchList(this.first)//搜素框递归查找分类
 
    },
     // 分类切换
    tabClass(type,index){
      console.log(type,index)
      if(type == '1'){
        this.num = index
      }else{
        this.sum = index
      }
      this.listType()
    },
    listType(){ //分类查找
      this.first = this.arrList
      console.log(this.first,'一级分类')
      this.second = this.first[this.num] && this.first[this.num].itemCategoryVOList ? this.first[this.num].itemCategoryVOList: ''
      console.log(this.second,'二级分类')
      this.tertiary = this.second[this.sum] && this.second[this.sum].itemCategoryVOList ? this.second[this.sum].itemCategoryVOList :''
      console.log(this.tertiary,'三级分类')
    },
    resFormat(arr) { //递归查找一级分类
      return arr.map(item=>{
        item.popover = false;
        if(item.itemCategoryVOList && item.itemCategoryVOList.length > 0){
            item.itemCategoryVOList = this.resFormat(item.itemCategoryVOList)
        }
        return item
      })
    },
    //原程搜索分类
    querySearchAsync(queryString, cb) {
      var restaurants = this.restaurants;
      var results = queryString ? restaurants.filter(this.createStateFilter(queryString)) : restaurants;
      this.searchChoose = null
      cb(results);
    },
    createStateFilter(queryString) {
      console.log(queryString)
      return (state) => {
        return state.value.toLowerCase().indexOf(queryString.toLowerCase()) >= 0;
      };
    },
    searchList(arr,value){ //搜索时递归查找分类
      arr.forEach(item => {
        if(value){
          item.value = `${value} > ${item.title}`
        }else{
          item.value = item.title
        }
        this.restaurants.push(item)
        if(item.itemCategoryVOList){
          return this.searchList(item.itemCategoryVOList,item.value)
        }
      });
    },
    handleSelect(e) { //搜索
      this.searchChoose = e
      this.getSearch()
    },
    getSearch() {
      let value = null
      let id = ''
      if(this.search || this.searchChoose){
        value = this.searchChoose
        this.restaurants.forEach(item=>{
          if(item.value === this.search){ //查找列表里和输入搜索框里的信息一样的执行
            value = item
          }
        })
        // 第二步 查找对应分类中的id
        if(value){
          if(value.level === 1){
            id = value.id
          }
          if(value.level > 1){
            id = value.previous
          }
          this.arrList = this.parentFormat(this.superList,id)
          this.listType()
          return
        }
      }
      this.arrList = this.superList
      this.listType()
    },
    parentFormat(arr,id){
      console.log(arr,id)
      if(!arr || !id){
        return 
      }
      let arrs = []
      // 递归查找上一级
      function des(arr,data){
        arr.forEach(item=>{
          if(item.id === id){
            if(data){
              return arrs.push(data)
            }
            return arrs.push(item)
          }
          if(item.itemCategoryVOList){
            return des(item.itemCategoryVOList,item)
          }
        })
      }
      des(arr,null)
      return arrs
    },
    //排序
    editSort() {},
  },
};
</script>

5,css样式

<style>
  .el-scrollbar__wrap {
  overflow-x: hidden !important;
}
</style>
<style  scoped>
 
.right-info-box {
  width: calc(100% - 150px);
}
.warp_group {
  background-color: #fff;
  padding: 24px;
}
 
  .group_card {
    background-color: #fff;
    padding: 20px;
    border-radius: 16px;
  }
.h_text {
  color: #333;
}
.line_box {
  width: 100%;
  padding: 20px;
  display: flex;
  justify-content: space-between;
}
 .group_flex {
    width: 33%;
  }
.group_item {
      display: flex;
      justify-content: space-between;
      align-items: center;
      background-color: #623ceb0d;
      padding: 10px;
      margin-right: 25px;
    }
.group_content_box {
  margin-right: 25px;
  border: 1px solid #dcdfe6;
  margin-top: 10px;
}
  .group_content_title {
    display: flex;
    justify-content: space-between;
    align-items: center;
    background-color: #623ceb0d;
    padding: 0px 20px;
    height: 48px;
    font-size: 14px;
  }
  .item_attr {
    border-bottom: 1px solid #dcdfe6;
    height: 48px;
    line-height: 48px;
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
    .avtive{
      border: 1px solid #637de6;
    }
    .item_name_box {
      display: flex;
      align-items: center;
      margin-left: 20px;
      width: 40%;
    }
    .img {
      width: 28px;
      height: 28px;
      border-radius: 50%;
    }
 
  .item_name_title {
    font-size: 14px;
    margin-left: 5px;
  }
.sort_btn {
  margin-top: 14px;
  display: flex;
  align-items: center;
  justify-content: flex-end;
}
.showIcon {
  opacity: 0;
  width: 14px;
  height: 14px;
  cursor: pointer;
}
  .showIcon:hover {
    opacity: 1;
  }
 
.item_handle {
  margin-right: 20px;
  width: 35%;
  text-align: right;
}
.handel_icon {
  margin-left: 10px;
  cursor: pointer;
}
.item_sort {
  width: 15%;
  text-align: center;
}
</style>

5,运行环境node.js

        运行命令:npm run dev

        打包命令:npm run build

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西安未央

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值