效果图
二、组件Filter-myBar.vue
<template>
<view class="sortContent">
<view class="sortCondition">
<view class="conditionList" v-for="(item,index) in topicArr" :key="index">
<view class="listParent" :data-tabtopic="sortlist[index]" :data-index="index" :data-name="item" @click="topicClick">
<text :class="item.length>4?'isovertext':''">{{item}}</text>
<u-icon :name="topicIndex==index && topicStatu ?'arrow-down':'arrow-up'" color="#000" size="12"></u-icon>
</view>
</view>
</view>
<!-- 筛选面板数据 -->
<view class="panelMask" v-if="topicStatu" @touchmove.stop.prevent="moveHandle"></view>
<view class="condition-panel" v-for="(item,index) in panelData" :key="index" v-if="topicIndex==index && topicStatu">
<view class="ranking" v-if="currentTap=='美食'">
<view class="panelList" v-for="(childitem,childindex) in item.children" :key="childindex"
:data-index="childindex" :data-name="childitem.name" @click="screenClick">
<text :class="deliciousindex==childindex?'delicious':''">{{childitem.name}}</text>
<text class="stopNumber" v-if="childitem.stopnum>0">{{childitem.stopnum}}</text>
</view>
</view>
<view class="ranking" v-else-if="currentTap=='智能排序'">
<view class="panelList" v-for="(recommendationitem,recommenindex) in item.children"
:key="recommenindex">
<view :data-index="recommenindex" :data-name="recommendationitem.name" @click="screenClick">
<text
:class="recommendationindex==recommenindex?'recommendation':''">{{recommendationitem.name}}</text>
</view>
</view>
</view>
<view class="nearby" v-else-if="currentTap=='附近'">
<view class="childTab" v-for="(childtabitem,childtanindex) in item.children" :key="childtanindex">
<view class="tabList">
<view :class=" tapindex==childtanindex?'tabtopic tabtopicActive':'tabtopic '"
:data-index="childtanindex" @click="tabClick">{{childtabitem.name}}
</view>
<view class="childContent" v-if="tapindex==childtanindex">
<scroll-view scroll-y="true">
<view class="contentList"
v-for="(childcontentitem,chilcontentindex) in childtabitem.children"
:key="chilcontentindex">
<view :class="contentindex==chilcontentindex &&tabName==childtabitem.name ?childcontentitem.children&&childcontentitem.children.length>0?
'contentopic contentopicActive':'contentopic contentActive':'contentopicdefault'"
:data-index="chilcontentindex" :data-name="childcontentitem.name"
:data-parentname="childtabitem.name"
:data-item="childtabitem"
@click.stop="contentClick">
{{childcontentitem.name}}
</view>
<view class="specific" v-if="contentindex==chilcontentindex &&
childcontentitem.children &&
childcontentitem.children.length>0">
<view class="specificList"
v-for="(specificitem,index) in childcontentitem.children"
:key="index" :data-index="index" :data-name="specificitem.name"
:data-parentname="childcontentitem.name"
@click.stop="specificClick">
<view :class="specificindex==index && specificName==childcontentitem.name?'specificActive':'specificcontent'">
{{specificitem.name}}
</view>
</view>
</view>
</view>
</scroll-view>
</view>
</view>
</view>
</view>
<view class="screen" v-else-if="currentTap=='筛选'">
<view class="screenList" v-for="(screenitem,screenindex) in item.children" :key="screenindex">
<view class="screenTopic">{{screenitem.name}}</view>
<view class="screenContent">
<view v-for="(screenchilditem,screenchildindex) in screenitem.children" :key="screenchildindex">
<view :class="screenchildindex==currentscreenindex?'screentext colorChange':'screentext'">
<view :data-index="screenchildindex" :data-name="screenchilditem.name"
@click="screenClick">{{screenchilditem.name}}</view>
</view>
</view>
</view>
</view>
<view class="operateBtn">
<button class="reset" @click="reset">重置</button>
<button class="sure" @click="sure">确定</button>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'sort',
props: {
sortlist: {
type: Array,
default: () => []
},
panelData: {
type: Array,
default: () => []
}
},
data() {
return {
topicArr: [],
panelArr: [],
currentTap: null,
topicIndex: 0,
tapindex: 0,
deliciousindex: 0,
recommendationindex: 0,
contentindex: 0,
specificindex: -1,
currentscreenindex: -1,
topicStatu: false,
currentspecific:null,
tabName:null,
specificName:null
}
},
mounted() {
this.topicArr = JSON.parse(JSON.stringify(this.sortlist))
},
methods: {
topicClick(e) {
const index = e.currentTarget.dataset.index;
const name = e.currentTarget.dataset.name;
const tabtopic = e.currentTarget.dataset.tabtopic;
this.currentTap = tabtopic;
if (this.topicIndex == index) {
this.topicStatu = !this.topicStatu
return
}
this.topicStatu = true;
this.topicIndex = index;
this.panelArr = this.panelData;
},
tabClick(e) {
console.log('tabClick',e);
const index = e.currentTarget.dataset.index;
this.tapindex = index;
// this.contentindex = -1;
},
contentClick(e) {
const index = e.currentTarget.dataset.index;
const name = e.currentTarget.dataset.name;
const parentname = e.currentTarget.dataset.parentname;
const item = e.currentTarget.dataset.item
this.tabName=parentname;
this.contentindex = index;
item.children.forEach((v,i)=>{
if(v.name == name){
if(v.children){
if(v.children.length){
this.topicStatu = true;
}else{
this.topicStatu = false;
}
}else{
this.topicStatu = false;
}
this.updatetopic(name)
}
})
},
specificClick(e) {
const index = e.currentTarget.dataset.index;
const name = e.currentTarget.dataset.name;
const parentname = e.currentTarget.dataset.parentname;
this.specificName=parentname;
this.specificindex = index;
this.topicStatu = false;
this.updatetopic(name)
},
screenClick(e) {
const index = e.currentTarget.dataset.index;
const name = e.currentTarget.dataset.name;
switch (this.currentTap) {
case "美食":
this.updatetopic(name)
this.deliciousindex = index;
this.topicStatu = false;
return;
case "智能排序":
this.updatetopic(name)
this.recommendationindex = index;
this.topicStatu = false;
return;
case "筛选":
this.currentspecific=name;
if (this.currentscreenindex == index) {
this.currentscreenindex = -1;
return
}
this.currentscreenindex = index;
return;
}
},
updatetopic(name){
let index=this.sortlist.indexOf(this.currentTap);
this.topicArr[index]=name
this.$emit("conditionName", name)
},
reset() {
this.currentscreenindex = -1;
},
sure(){
this.topicStatu = false;
this.$emit("conditionName", this.currentspecific)
}
}
}
</script>
<style lang="less">
.sortContent {
position: relative;
height: 100vh;
}
.sortCondition {
display: flex;
align-items: center;
padding: 20rpx 0;
height: 100rpx;
box-sizing: border-box;
}
.conditionList{
flex: 1;
display: flex;
justify-content: center;
.listParent{
view {
margin-left: 6rpx !important;
margin-top: 6rpx !important;
}
}
}
.listParent {
display: flex;
align-items: center;
/* margin-left: 28rpx; */
justify-content: center;
/* width: 180rpx; */
position: relative;
}
.listParent .isovertext{
width: 124rpx;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
text-align: center;
}
.conditionList .iconfont {
width: 0;
transform: scale3d(1.5, 1.5, 1.5);
}
.condition-panel {
/* padding: 20rpx 60rpx; */
/* height: 60%; */
position: absolute;
left: 0;
right: 0;
overflow: auto;
background-color: #FFFFFF;
}
.panelMask {
position: absolute;
left: 0;
right: 0;
top: 100rpx;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
}
.ranking {
padding: 0 60rpx;
}
.panelList {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx 0;
}
.stopNumber {
color: #999999;
}
.nearby {
display: flex;
align-items: center;
flex-direction: column;
position: relative;
height: 100%;
}
.childTab,
.tabList,
.contentList {
display: flex;
align-items: flex-start;
width: 100%;
}
.tabtopic {
width: 300rpx;
padding: 20rpx 60rpx;
box-sizing: border-box;
color: #101010;
/* flex: 0.3; */
}
.tabtopicActive {
color: #007AFF;
background-color: rgba(0, 0, 0, 0.05);
}
.specific {
position: absolute;
right: 0;
top: 0;
bottom: 0;
left: 180rpx;
background-color: rgba(0, 0, 0, 0.05);
overflow: scroll;
}
.specificActive {
color: #007AFF !important;
}
.contentopic {
padding: 20rpx 0;
color: #101010;
padding-left: 40rpx;
width: 180rpx;
box-sizing: border-box;
}
.contentopicdefault {
padding: 20rpx 0;
color: #101010;
padding-left: 40rpx;
width: auto;
box-sizing: border-box;
}
.contentActive {
color: #007AFF;
width: auto;
}
.contentopicActive {
color: #007AFF;
background-color: rgba(0, 0, 0, 0.05);
}
.contentopicActive,
.tabtopicActive {
position: relative;
}
.contentopicActive::before,
.tabtopicActive::before {
content: '';
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 6rpx;
background-color: #007AFF;
}
.childContent {
flex: 1;
position: absolute;
right: 0;
top: 0;
left: 300rpx;
bottom: 0;
background-color: rgba(0, 0, 0, 0.05);
overflow: scroll;
}
.specificList view {
padding: 20rpx 0;
color: #101010;
padding-left: 40rpx;
box-sizing: border-box;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.delicious,.recommendation{
color: #007AFF;
}
.screen {
padding: 20rpx 60rpx 140rpx;
}
.screenContent {
display: flex;
align-items: center;
flex-wrap: wrap;
justify-content: space-between;
}
.screentext {
width: 160rpx;
height: 60rpx;
border-radius: 8rpx;
border: 1px solid #999999;
display: flex;
align-items: center;
justify-content: center;
margin-top: 20rpx;
color: #101010;
}
.colorChange {
color: #007AFF;
background-color: #DEE7FF;
position: relative;
overflow: hidden;
border: 1px solid #007AFF;
}
.colorChange::before {
content: '';
position: absolute;
width: 60rpx;
height: 60rpx;
bottom: -30rpx;
right: -30rpx;
transform: rotate(45deg);
background: #007AFF;
}
.colorChange::after {
content: '';
position: absolute;
width: 17rpx;
height: 9rpx;
border: 2rpx solid #fff;
bottom: 14rpx;
right: 5rpx;
border-top: none;
border-right: none;
background: transparent;
transform: rotate(-45deg);
}
.operateBtn{
position: absolute;
left: 0;
bottom: 20rpx;
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
}
.operateBtn button{
width: 160rpx;
font-size: 28rpx;
background-color: #007AFF;
color: #FFFFFF;
}
.operateBtn .reset{
background-color: #FFFFFF;
color: #808080;
}
</style>
三、使用
<template>
<view>
<filterBar :sortlist="topicArr" :panelData="panelArr" @conditionName="conditionName"></filterBar>
</view>
</template>
<script>
import filterBar from '@/components/Filter-myBar.vue'
export default {
components: {
filterBar
},
data() {
return {
"topicArr": ["附近", "美食", "智能排序", "筛选"],
"panelArr": [{
"name": "附近",
"children": [{
"name": "附近",
"children": [
{
"name": "附近(智能范围)"
},
{
"name": "500米以内"
},
{
"name": "1000米以内"
},
{
"name": "1500米以内"
},
{
"name": "2000米以内"
}
]
},
{
"name": "行政区/商区",
"children": [{
"name": "热门商区",
"children": [{
"name": "体育中心"
},
{
"name": "新城区"
}
]
},
{
"name": "全城",
"children": []
},
{
"name": "高新区",
"children": [{
"name": "全部高新区"
}, {
"name": "北郊"
}, {
"name": "南郊"
},
{
"name": "东郊"
},
{
"name": "西郊"
}]
}
]
},
{
"name": "地铁",
"children": [{
"name": "2号线",
"children": [{
"name": "北站"
},
{
"name": "未央站"
},
{
"name": "龙首站"
},
{
"name": "咸宁站"
}
]
},
{
"name": "3号线",
"children": [{
"name": "太白站"
}, {
"name": "玉华站"
},
]
},
{
"name": "12号线",
"children": [{
"name": "玉祥门站"
}, {
"name": "鱼化寨站"
},
]
},
{
"name": "6号线",
"children": [{
"name": "南站"
}, {
"name": "北站"
},
{
"name": "东站"
},
]
}
]
}
]
}, {
"name": "美食",
"children": [{
"name": "全部美食",
"stopnum": 0
},
{
"name": "湘菜",
"stopnum": 1
},
{
"name": "川菜",
"stopnum": 2
},
{
"name": "徽菜",
"stopnum": 3
}
]
},
{
"name": "综合排序",
"children": [{
"name": "综合排序"
},
{
"name": "距离最近"
},
{
"name": "人气优先"
},
{
"name": "好评优先"
},
{
"name": "起送价最低"
},
{
"name": "配送最快"
}
]
},
{
"name": "筛选",
"children": [{
"name": "价格",
"children": [{
"name": "50以下"
}, {
"name": "50-100"
},
{
"name": "100-300"
},
{
"name": "300以上"
}
]
}]
}
]
}
},
methods:{
conditionName(name){
console.log('name',name);
}
}
}
</script>
<style lang="less">
</style>