概述
一款基于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>
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