<template>
|
<view class="tree-filter">
|
<view class="tree-filter-input" @click="show">
|
<slot>
|
|
</slot>
|
</view>
|
|
<view class="tree-filter-tree-cover" v-if="isOpened" @click="handleClose"></view>
|
<view class="tree-filter-tree-dialog" v-if="isOpened">
|
<view class="tree-filter-popper__arrow"></view>
|
<view class="dialog-caption">
|
<view class="title-area">
|
<text class="dialog-title">{{popupTitle}}</text>
|
</view>
|
<view class="dialog-close" @click="handleClose">
|
<view class="dialog-close-plus" data-id="close"></view>
|
<view class="dialog-close-plus dialog-close-rotate" data-id="close"></view>
|
</view>
|
</view>
|
<view v-if="filter"
|
style="margin-left:40rpx;margin-right:40rpx;;margin-top: 40rpx;border-bottom:1px solid #eee;padding-bottom:20rpx;display:flex;color:#000">
|
<input v-model="search" style="height:60rpx;line-height:60rpx;color:#000" placeholder="请输入搜索内容"></input>
|
<view @click="()=>{search='';updateSearch()}"
|
style="height:60rpx;line-height:60rpx;margin-left:auto;margin-right:0rpx">清空</view>
|
<view @click="updateSearch" style="height:60rpx;line-height:60rpx;margin-left:auto;margin-right:0rpx">搜索
|
</view>
|
</view>
|
<view>
|
<!-- 渲染多级树,首先确认层级? -->
|
<view v-if="currentLevel===-1" class="tree-filter-nodes">
|
<!-- 暂时跟节点 -->
|
<view v-for="(item,index) of localdata" :key="item.value" class="tree-filter-node"
|
@click="selecteRow(item)">
|
<view>{{item.label}}</view>
|
<view class="arrow" v-if="item.children&&item.children.length>0">
|
<uni-icons type="right"></uni-icons>
|
|
</view>
|
</view>
|
</view>
|
<view v-else>
|
<view class="tree-filter-top-titles">
|
<view v-for="(item,index) of currentNodes" :key="item.value"
|
@click="selecteRowCurrentNodesOne(item,index)" class="tree-filter-top-title">
|
<view>{{item.label || '-'}}</view>
|
<view class="arrow"><uni-icons type="right" style="color: lightgray;"></uni-icons></view>
|
</view>
|
<view class="tree-filter-top-title-tip">
|
请选择
|
</view>
|
</view>
|
<view class="tree-filter-nodes">
|
<view v-for="(item,index) of currentNodes[currentLevel].children" :key="item.value"
|
class="tree-filter-node" @click="selecteRow(item)">
|
<view>{{item.label}}</view>
|
<view class="arrow" v-if="item.children&&item.children.length>0">
|
<uni-icons type="right"></uni-icons>
|
</view>
|
</view>
|
</view>
|
</view>
|
</view>
|
</view>
|
</view>
|
</template>
|
<!-- 多级带搜索插叙功能的tree -->
|
<script>
|
export default {
|
name: "tree-filter",
|
data() {
|
return {
|
isOpened: false,
|
search: '',
|
currentLevel: -1,
|
currentNodes: [], //数组存储
|
currentValue: {}
|
};
|
},
|
methods: {
|
|
async updateSearch() {
|
//todo 递归搜索下面的数据,,并标记为可展示的
|
console.log('updateSearch', this.localdata)
|
await this.$emit('search', this.search)
|
// console.log('updateSearch',this.localdata)
|
|
// setTimeout(() => {
|
// console.log('updateSearch2 setTimeout', this.localdata)
|
// //清空
|
// if (this.search) {
|
// this.selectedClear()
|
// }
|
// if(!this.search){
|
// //其他的也恢复
|
// this.selectedClear()
|
// }
|
// }, 200)
|
},
|
initData(){
|
|
},
|
//数据
|
selectedClear() {
|
//清空选择的数据
|
//当前层级和当前节点?
|
this.currentLevel = -1
|
this.currentNodes = []
|
this.currentValue = {}
|
this.$forceUpdate()
|
},
|
selectedSet() {
|
//设置处理的级别,需要第几个节点
|
|
},
|
selecteRowCurrentNodesOne(item, index) {
|
//选择的是最上面的
|
var lens = this.currentNodes.length - index
|
this.currentNodes.splice(index, lens)
|
this.currentLevel -= (lens + 0)
|
console.log(' this.currentNodes', this.currentNodes,this.currentLevel)
|
|
},
|
selecteRow(row) {
|
//选择某一个
|
console.log('selecteRow', row)
|
if (row.children && row.children.length > 0) {
|
//选择节点
|
this.currentNodes.push(row)
|
this.currentLevel += 1
|
|
} else {
|
//选择的是value
|
if (this.currentLevel === -1) {
|
//直接选择的
|
this.currentValue = row
|
} else {
|
this.currentValue = row
|
|
}
|
this.hide()
|
this.$emit('change', {
|
detail: {
|
value: [row]
|
}
|
})
|
|
|
}
|
},
|
//显示
|
show() {
|
this.isOpened = true
|
setTimeout(() => {
|
this.$refs.pickerView&&this.$refs.pickerView.updateData({
|
treeData: this._treeData,
|
selected: this.selected,
|
selectedIndex: this.selectedIndex
|
})
|
}, 200)
|
this.$emit('popupopened')
|
},
|
hide() {
|
this.isOpened = false
|
this.$emit('popupclosed')
|
},
|
handleClose() {
|
this.hide()
|
|
},
|
},
|
props: {
|
filter: {
|
type: Boolean,
|
default: true
|
},
|
placeholder: {
|
type: String,
|
default: '请选择'
|
},
|
localdata: {
|
type: [Array, Object],
|
default () {
|
return []
|
}
|
},
|
selectConfirmTitle: {
|
type: String,
|
default: ''
|
}
|
}
|
}
|
</script>
|
|
<style lang="scss">
|
.tree-filter {
|
.tree-filter-top-titles {
|
display: flex;
|
margin-bottom: 0rpx;
|
overflow-x: scroll;
|
flex-wrap: wrap;
|
padding-left: 40rpx;
|
padding-right: 40rpx;
|
padding-top: 20rpx;
|
|
.tree-filter-top-title {
|
margin-right: 40rpx;
|
text-align: left;
|
// color: darkgray;
|
color: #333;
|
display: flex;
|
|
.arrow {
|
margin-left: 30rpx;
|
}
|
}
|
|
.tree-filter-top-title-tip {
|
margin-right: 40rpx;
|
text-align: left;
|
color: darkgray;
|
display: inline-block;
|
}
|
|
.tree-filter-top-title::last-child {
|
// color: #333;
|
}
|
}
|
|
.tree-filter-nodes {
|
padding-left: 40rpx;
|
padding-right: 40rpx;
|
overflow-y: scroll;
|
max-height: 80vh;
|
|
.tree-filter-node {
|
display: flex;
|
color: #333;
|
|
.arrow {
|
margin-left: auto;
|
margin-right: 0rpx;
|
}
|
}
|
}
|
|
.tree-filter-tree-cover {
|
position: fixed;
|
left: 0;
|
top: 0;
|
right: 0;
|
bottom: 0;
|
background-color: rgba(0, 0, 0, .4);
|
/* #ifndef APP-NVUE */
|
display: flex;
|
/* #endif */
|
flex-direction: column;
|
z-index: 100;
|
}
|
|
.tree-filter-tree-dialog {
|
position: fixed;
|
padding: 20rpx;
|
padding-top: 40rpx;
|
left: 0;
|
/* #ifndef APP-NVUE */
|
top: 20%;
|
/* #endif */
|
/* #ifdef APP-NVUE */
|
top: 200px;
|
/* #endif */
|
right: 0;
|
bottom: 0;
|
background-color: #FFFFFF;
|
border-top-left-radius: 10px;
|
border-top-right-radius: 10px;
|
/* #ifndef APP-NVUE */
|
display: flex;
|
/* #endif */
|
flex-direction: column;
|
z-index: 102;
|
overflow: hidden;
|
/* #ifdef APP-NVUE */
|
width: 750rpx;
|
/* #endif */
|
}
|
|
/* picker 弹出层通用的指示小三角, todo:扩展至上下左右方向定位 */
|
/* #ifndef APP-NVUE */
|
.tree-filter-popper__arrow,
|
.tree-filter-popper__arrow::after {
|
position: absolute;
|
display: block;
|
width: 0;
|
height: 0;
|
border-color: transparent;
|
border-style: solid;
|
border-width: 6px;
|
}
|
|
.tree-filter-popper__arrow {
|
filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
|
top: -6px;
|
left: 10%;
|
margin-right: 3px;
|
border-top-width: 0;
|
border-bottom-color: #EBEEF5;
|
}
|
|
.tree-filter-popper__arrow::after {
|
content: " ";
|
top: 1px;
|
margin-left: -6px;
|
border-top-width: 0;
|
border-bottom-color: #fff;
|
}
|
|
/* #endif */
|
.dialog-caption {
|
position: relative;
|
/* #ifndef APP-NVUE */
|
display: flex;
|
/* #endif */
|
flex-direction: row;
|
/* border-bottom: 1px solid #f0f0f0; */
|
}
|
|
.dialog-title {
|
/* font-weight: bold; */
|
line-height: 44px;
|
}
|
|
.dialog-close {
|
position: absolute;
|
top: 0;
|
right: 0;
|
bottom: 0;
|
/* #ifndef APP-NVUE */
|
display: flex;
|
/* #endif */
|
flex-direction: row;
|
align-items: center;
|
padding: 0 15px;
|
}
|
|
.dialog-close-plus {
|
width: 16px;
|
height: 2px;
|
background-color: #666;
|
border-radius: 2px;
|
transform: rotate(45deg);
|
}
|
|
.dialog-close-rotate {
|
position: absolute;
|
transform: rotate(-45deg);
|
}
|
|
}
|
</style>
|