基于vue写的自定义商品三级分类,包括搜索分类全是前端控制
技术:vue.js
概述
一款基于vue所写的商品三级分类,包括搜所全是前端的控制,这里的搜索用到递归写法供大家参考
详细
1,项目结构
2,
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>
3,
<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>
4,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
本实例支付的费用只是购买源码的费用,如有疑问欢迎在文末留言交流,如需作者在线代码指导、定制等,在作者开启付费服务后,可以点击“购买服务”进行实时联系,请知悉,谢谢
手机上随时阅读、收藏该文章 ?请扫下方二维码