- 效果
- 数据准备
javascript
[{"id":1,"name":"测试校区1","children":[{"id":133,"value":"教学楼","children":[{"id":153,"value":"一楼","children":[{"id":156,"value":"教师食堂","children":[]},{"id":155,"value":"学生食堂","children":[]},{"id":154,"value":"体育器材室","children":[]}]},{"id":134,"value":"三楼","children":[{"id":136,"value":"301","children":[]}]}]}]},{"id":39,"value":"测试1234","children":[{"id":121,"value":"二级场地测试","children":[{"id":122,"value":"三级场地测试","children":[]}]}]},{"id":37,"value":"柔道馆","children":[]}]
- 页面代码
javascript
<template>
<u-popup
:show.sync="show"
mode="bottom"
@click="close()">
<view
class="t-pop"
@tap.stop>
<view class="pop-main">
<view class="header">
<view
class="cancel"
@click="close()"
>取消</view
>
<view class="title">{{ title }}</view>
<view
class="confirm"
@click="onOK()"
><text>确定</text></view
>
</view>
<view class="select-container">
<view
v-for="(tab , index) in tabs"
:key="index"
@click="changeSwp(tab.id, index)"
class="date-c "
:class="{select_item: tabIndex === tab.id}">
<text>{{tab.label}}</text>
</view>
</view>
<swiper
class="swiper"
:disable-touch="true"
:current-item-id="tabIndex">
<swiper-item v-for="(tab, index) in tabs" :key="index" :item-id="tab.id">
<picker-view
v-if="selectOption[index] && selectOption[index].length > 0"
:value="tab.select"
@change="bindChange($event, index)"
:indicator-style="indicatorStyle"
class="picker-view">
<picker-view-column>
<view v-for="(item, index) in selectOption[index]"
:key="index"
class="item">
{{item.label}}
</view>
</picker-view-column>
</picker-view>
<u-empty
v-else
text="暂无数据"
icon="../../static/empty.png"></u-empty>
</swiper-item>
</swiper>
</view>
</view>
<u-toast ref="uToast"></u-toast>
</u-popup>
</template>
<script>
export default {
props: {
show: {
type: Boolean,
default: false
},
title: {
type: String,
default: ''
},
data: {
type: Array,
default() {
return []
},
},
params: {
type: Object,
default() {
return {}
}
}
},
data() {
return {
tabs: [],
tabIndex: '0',
indicatorStyle: `height: 50px;`,
selectOption: [],
parentMap: {},
isInit: false,
}
},
watch: {
// 使用watch来响应数据的变化
show: {
handler: function (val) {
if (val) {
this.init()
}
},
immediate: true
}
},
created() {
this.init()
},
methods: {
bindChange(e,index){
console.log('选择第'+index+'列第'+e.detail.value[0]+'行')
console.log(this.selectOption[index][Number.parseInt(e.detail.value[0])])
const selected = this.selectOption[index][Number.parseInt(e.detail.value[0])]
this.tabs[index].label = selected.label
this.tabs[index].value = selected.value
// 后面的清空
for(let i = 0; i < this.tabs.length; i++){
if(i > index){
this.tabs[i].label = '请选择'
this.tabs[i].value = ''
}
}
for(let i = 0; i < this.selectOption.length; i++){
if(i === index +1){
this.selectOption[i] = this.parentMap[selected.value] || []
}else if(i > index + 1){
this.selectOption[i] = []
}
}
},
init() {
if(this.isInit) return
const maxDepth = this.getDepth(this.data)
if(maxDepth === 0){
return
}
this.tabs = []
this.fetchTree(this.data, 0)
console.log(this.parentMap)
for(let i = 0; i < maxDepth; i++){
let tab = {id: i+'', label: '请选择', value: ''}
if(i === 0){
this.selectOption[0] = this.parentMap[0] || []
if(this.selectOption[0].length > 0){
tab.label = this.selectOption[0][0].label
tab.value = this.selectOption[0][0].value
}
}
this.tabs.push(tab)
this.isInit = true
}
},
fetchTree(nodes, parentId){
if(nodes != null && nodes.length > 0){
this.parentMap[parentId] = nodes.map(node => {
return {
label: node[this.params.label || 'label'],
value: node[this.params.value || 'value']
}
})
nodes.forEach(node => {
if(node.children != null && node.children.length > 0){
this.fetchTree(node.children, node[this.params.value || 'value'])
}
})
}
},
getDepth(tree){
if (!tree || tree.length === 0) return 0;
return Math.max(...tree.map(node => {
const childrenDepth = node.children ? this.getDepth(node.children) : 0;
return 1 + childrenDepth;
}));
},
close() {
this.$emit('close')
},
onOK() {
const hasSelect = this.tabs.filter(tab => tab.value)
if(hasSelect.length === 0){
this.$refs.uToast.show({
message: '请选择',
type: 'error'
})
}else {
const last = hasSelect[hasSelect.length - 1 ]
const children = this.parentMap[last.value]
if(children && children.length > 0){
this.$refs.uToast.show({
message: '请选择到最后一层',
type: 'error'
})
}else{
this.$emit('submit', {value: last.value, path: hasSelect.map(item => item.label).join('/')})
}
}
},
changeSwp(i, index){
this.tabIndex = i
if (index === 0){
return
}
const parent = this.tabs[index - 1]
this.selectOption[index] = this.parentMap[parent.value] || []
if(this.selectOption[index].length >0){
this.tabs[index].label = this.selectOption[index][0].label
this.tabs[index].value = this.selectOption[index][0].value
}
}
}
}
</script>
<style lang="scss" scoped>
.t-pop {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
.pop-main {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
background-color: #fff;
border-radius: 24px;
height: 750rpx;
width: 100%;
}
}
.swiper {
height: 750rpx !important;
width: 100vw;
}
.header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
width: 100%;
padding: 26rpx 0;
border-bottom: 1rpx solid rgba(#000B2E, .08);
.cancel {
padding-left: 32rpx;
font-size: 28rpx;
color: rgba(#000B2E, .65);
}
.title {
font-weight: 600;
font-size: 32rpx;
color: rgba(#000B2E, .85);
}
.confirm {
padding-right: 32rpx;
font-size: 28rpx;
color: #2AD18B;
}
}
.select-container {
width: 100%;
padding: 24rpx 32rpx;
display: flex;
align-items: center;
.date-c {
margin-left: 32rpx;
//width: 164rpx;
position: relative;
.active-date {
position: absolute;
bottom: -24rpx;
left: 58rpx;
width: 48rpx;
height: 6rpx;
background: #2AD18B;
border-radius: 4rpx;
}
}
.time-c {
margin-left: 52rpx;
width: 76rpx;
position: relative;
.active-time {
position: absolute;
bottom: -24rpx;
left: 16rpx;
width: 48rpx;
height: 6rpx;
background: #2AD18B;
border-radius: 4rpx;
}
}
}
.calendar {
display: flex;
flex-wrap: wrap;
flex-direction: row;
align-items: center;
width: 100vw;
position: relative;
}
.ca-top {
width: 14.2vw;
height: 112rpx;
display: flex;
justify-content: center;
align-items: center;
z-index: 10;
font-size: 32rpx;
color: rgba(#000B2E, .85);
}
.cell {
width: 60rpx;
height: 60rpx;
display: flex;
justify-content: center;
align-items: center;
align-content: center;
border-radius: 30rpx;
font-size: 32rpx;
color: rgba(#000B2E, .85);
}
.cell-active {
background-color: #2AD18B;
color: #fff;
width: 96rpx;
height: 112rpx;
border-radius: 8rpx;
}
.cabg {
display: flex;
justify-content: center;
align-items: center;
width: 100vw;
position: absolute;
z-index: 9;
height: 320rpx;
font-size: 320rpx;
font-weight: bold;
color: rgba(0, 11, 46, 0.05);
line-height: 348rpx;
}
.picker-view {
width: 100%;
height: 750rpx !important;
// margin-top: 20rpx;
::deep .uni-picker-view-content {
padding: 0;
}
}
.item {
height: 50px;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
}
.select_item {
color: #2AD18B;
}
</style>
- 页面引用
javascript
<Cascader
@close="showType2 = false"
:data="siteList"
:show="showType2"
@submit="siteChange"
title="选择场地"
:params="{
value: 'id',
label: 'siteName',
}"
/>