|
|
<template value="aui-picker">
|
|
|
<view class="aui-picker" v-if="SHOW" :class="{
|
|
|
'aui-picker-in': FADE==1,
|
|
|
'aui-picker-out': FADE==0}"
|
|
|
@click.stop="close"
|
|
|
>
|
|
|
<view class="aui-mask"></view>
|
|
|
<view class="aui-picker-main">
|
|
|
<view class="aui-picker-header">
|
|
|
<view class="aui-picker-title" v-if="title">{{title}}</view>
|
|
|
<view class="aui-picker-close iconfont iconclose" @click.stop="close"></view>
|
|
|
</view>
|
|
|
<view class="aui-picker-nav">
|
|
|
<view class="aui-picker-navitem"
|
|
|
v-if="nav.length>0"
|
|
|
v-for="(item, index) in nav"
|
|
|
:key="index"
|
|
|
:data-index="index"
|
|
|
:class="[index==navCurrentIndex ? 'active' : '', 'aui-picker-navitem-'+index]"
|
|
|
:style="{margin: nav.length>2 ? '0 10px 0 0' : '0 30px 0 0'}"
|
|
|
@click.stop="_changeNav($event)"
|
|
|
>{{item.value}}</view>
|
|
|
<view class="aui-picker-navitem"
|
|
|
:key="nav.length"
|
|
|
:data-index="nav.length"
|
|
|
:class="[nav.length==navCurrentIndex ? 'active' : '', 'aui-picker-navitem-'+nav.length]"
|
|
|
:style="{margin: nav.length>2 ? '0 10px 0 0' : '0 30px 0 0'}"
|
|
|
@click.stop="_changeNav($event)"
|
|
|
>请选择</view>
|
|
|
<view class="aui-picker-navborder" :style="{left: navBorderLeft+'px'}"></view>
|
|
|
</view>
|
|
|
<view class="aui-picker-content">
|
|
|
<view class="aui-picker-lists">
|
|
|
<view class="aui-picker-list"
|
|
|
v-for="(list, index) in queryItems.length + 1"
|
|
|
:key="index"
|
|
|
:data-index="index"
|
|
|
:class="[index==navCurrentIndex ? 'active' : '']"
|
|
|
>
|
|
|
<view class="aui-picker-list-warp" v-if="index == 0">
|
|
|
<view class="aui-picker-item"
|
|
|
v-for="(item, key) in items"
|
|
|
v-if="item.pid=='0'"
|
|
|
:key="key"
|
|
|
:data-pindex="index"
|
|
|
:data-index="key"
|
|
|
:data-id="item.id"
|
|
|
:data-pid="item.pid"
|
|
|
:data-value="item.value"
|
|
|
:class="{'active': result.length>index && result[index].id==item.id}"
|
|
|
:style="{'background': touchConfig.index==key && touchConfig.pindex==index ? touchConfig.style.background : ''}"
|
|
|
@click.stop="_chooseItem($event)"
|
|
|
@touchstart="_btnTouchStart($event)"
|
|
|
@touchmove="_btnTouchEnd($event)"
|
|
|
@touchend="_btnTouchEnd($event)"
|
|
|
>{{item.value}}</view>
|
|
|
</view>
|
|
|
<view class="aui-picker-list-warp" v-else>
|
|
|
<view class="aui-picker-item"
|
|
|
v-for="(item, key) in queryItems[index-1]"
|
|
|
:key="key"
|
|
|
:data-pindex="index"
|
|
|
:data-index="key"
|
|
|
:data-id="item.id"
|
|
|
:data-pid="item.pid"
|
|
|
:data-value="item.value"
|
|
|
:class="{'active': result.length>index && result[index].id==item.id}"
|
|
|
:style="{'background': touchConfig.index==key && touchConfig.pindex==index ? touchConfig.style.background : ''}"
|
|
|
@click.stop="_chooseItem($event)"
|
|
|
@touchstart="_btnTouchStart($event)"
|
|
|
@touchmove="_btnTouchEnd($event)"
|
|
|
@touchend="_btnTouchEnd($event)"
|
|
|
>{{item.value}}</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
export default {
|
|
|
name: 'aui-picker',
|
|
|
props: {
|
|
|
title: { //标题
|
|
|
type: String,
|
|
|
default: ''
|
|
|
},
|
|
|
layer: { //控制几级联动,默认无限级(跟随数据有无下级)
|
|
|
type: Number,
|
|
|
default: null
|
|
|
},
|
|
|
data: { //数据 如:[{id: '', value: '', childs: [{id: '', value: ''}]}]
|
|
|
type: Array,
|
|
|
default (){
|
|
|
return [
|
|
|
// [{id: '', value: '', childs: [{id: '', value: ''}]}]
|
|
|
]
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
data(){
|
|
|
return {
|
|
|
SHOW: false,
|
|
|
FADE: -1,
|
|
|
nav: [],
|
|
|
items: [],
|
|
|
queryItems: [],
|
|
|
navCurrentIndex: 0,
|
|
|
navBorderLeft: 40,
|
|
|
result: [],
|
|
|
touchConfig: {
|
|
|
index: -1,
|
|
|
pindex: -1,
|
|
|
style: {
|
|
|
color: '#197DE0',
|
|
|
background: '#EFEFEF'
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
created(){
|
|
|
const _this = this;
|
|
|
},
|
|
|
watch:{
|
|
|
data(){
|
|
|
const _this = this;
|
|
|
const data = _this.data;
|
|
|
_this.items = _this._flatten(data, '0')
|
|
|
}
|
|
|
},
|
|
|
mounted(){
|
|
|
|
|
|
},
|
|
|
methods:{
|
|
|
// 打开
|
|
|
open(){
|
|
|
const _this = this;
|
|
|
_this.reset(); //打开时重置picker
|
|
|
return new Promise(function(resolve, reject){
|
|
|
_this.SHOW = true;
|
|
|
_this.FADE = 1;
|
|
|
resolve();
|
|
|
});
|
|
|
},
|
|
|
// 关闭
|
|
|
close(){
|
|
|
const _this = this;
|
|
|
return new Promise(function(resolve, reject){
|
|
|
_this.FADE = 0;
|
|
|
const _hidetimer = setTimeout(()=>{
|
|
|
_this.SHOW = false;
|
|
|
_this.FADE = -1;
|
|
|
clearTimeout(_hidetimer);
|
|
|
resolve();
|
|
|
},100)
|
|
|
});
|
|
|
},
|
|
|
//重置
|
|
|
reset(){
|
|
|
const _this = this;
|
|
|
_this.queryItems = [];
|
|
|
_this.nav = [];
|
|
|
_this.navBorderLeft = 40;
|
|
|
_this.navCurrentIndex = 0;
|
|
|
_this.result = [];
|
|
|
},
|
|
|
//导航栏切换
|
|
|
_changeNav(e){
|
|
|
const _this = this;
|
|
|
const index = Number(e.currentTarget.dataset.index);
|
|
|
_this.navCurrentIndex = index;
|
|
|
const _el = uni.createSelectorQuery().in(this).select(".aui-picker-navitem-"+index);
|
|
|
_el.boundingClientRect(data => {
|
|
|
_this.navBorderLeft = data.left + 20;
|
|
|
}).exec();
|
|
|
},
|
|
|
//数据选择
|
|
|
_chooseItem(e){
|
|
|
const _this = this;
|
|
|
const id = e.currentTarget.dataset.id;
|
|
|
const value = e.currentTarget.dataset.value;
|
|
|
const pid = e.currentTarget.dataset.pid;
|
|
|
const _arr = [];
|
|
|
_this.result[_this.navCurrentIndex] = {id: id, value: value, pid: pid};
|
|
|
if(
|
|
|
(!_this._isDefine(_this.layer) && _this._isDefine(_this._deepQuery(_this.data, id).childs))
|
|
|
||
|
|
|
(_this.navCurrentIndex < (Number(_this.layer) - 1) && _this._isDefine(_this._deepQuery(_this.data, id).childs))
|
|
|
)
|
|
|
{ //有下级数据
|
|
|
_this._deepQuery(_this.data, id).childs.forEach(function(item, index){
|
|
|
_arr.push({id: item.id, value: item.value, pid: id});
|
|
|
});
|
|
|
if(_this.navCurrentIndex == _this.queryItems.length)
|
|
|
{ //选择数据
|
|
|
_this.queryItems.push(_arr);
|
|
|
_this.nav.push({value: value});
|
|
|
}
|
|
|
else
|
|
|
{ //重新选择数据
|
|
|
_this.queryItems.splice(_this.navCurrentIndex+1, 1);
|
|
|
_this.nav.splice(_this.navCurrentIndex+1, 1);
|
|
|
_this.queryItems.splice(_this.navCurrentIndex, 1, _arr);
|
|
|
_this.nav.splice(_this.navCurrentIndex, 1, {value: value});
|
|
|
}
|
|
|
_this.navCurrentIndex = _this.navCurrentIndex + 1;
|
|
|
const _el = uni.createSelectorQuery().in(this).select(".aui-picker-navitem-"+_this.navCurrentIndex);
|
|
|
setTimeout(()=>{
|
|
|
_el.boundingClientRect(data => {
|
|
|
_this.navBorderLeft = data.left + 20;
|
|
|
}).exec();
|
|
|
},100)
|
|
|
}
|
|
|
else
|
|
|
{ //无下级数据
|
|
|
_this.close().then(()=>{
|
|
|
_this.$emit("callback", {status: 0, data: _this.result});
|
|
|
});
|
|
|
}
|
|
|
},
|
|
|
//递归遍历——将树形结构数据转化为数组格式
|
|
|
_flatten(tree, pid) {
|
|
|
return tree.reduce((arr, {id, value, childs = []}) =>
|
|
|
arr.concat([{id, value, pid}], this._flatten(childs, id)), [])
|
|
|
},
|
|
|
//根据id查询对应的数据(如查询id=10100对应的对象)
|
|
|
_deepQuery(tree, id) {
|
|
|
let isGet = false;
|
|
|
let retNode = null;
|
|
|
function deepSearch(tree, id){
|
|
|
for(let i = 0; i < tree.length; i++) {
|
|
|
if(tree[i].childs && tree[i].childs.length > 0) {
|
|
|
deepSearch(tree[i].childs, id);
|
|
|
}
|
|
|
if(id === tree[i].id || isGet) {
|
|
|
isGet||(retNode = tree[i]);
|
|
|
isGet = true;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
deepSearch(tree, id);
|
|
|
return retNode;
|
|
|
},
|
|
|
/***判断字符串是否为空
|
|
|
@param {string} str 变量
|
|
|
@example: aui.isDefine("变量");
|
|
|
*/
|
|
|
_isDefine(str){
|
|
|
if (str==null || str=="" || str=="undefined" || str==undefined || str=="null" || str=="(null)" || str=='NULL' || typeof (str)=='undefined'){
|
|
|
return false;
|
|
|
}else{
|
|
|
str = str + "";
|
|
|
str = str.replace(/\s/g, "");
|
|
|
if (str == ""){return false;}
|
|
|
return true;
|
|
|
}
|
|
|
},
|
|
|
_btnTouchStart(e){
|
|
|
const _this = this,
|
|
|
index = Number(e.currentTarget.dataset.index),
|
|
|
pindex = Number(e.currentTarget.dataset.pindex);
|
|
|
_this.touchConfig.index = index;
|
|
|
_this.touchConfig.pindex = pindex;
|
|
|
},
|
|
|
_btnTouchEnd(e){
|
|
|
const _this = this,
|
|
|
index = Number(e.currentTarget.dataset.index),
|
|
|
pindex = Number(e.currentTarget.dataset.pindex);
|
|
|
_this.touchConfig.index = -1;
|
|
|
_this.touchConfig.pindex = -1;
|
|
|
},
|
|
|
}
|
|
|
}
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
/* ====================
|
|
|
多级联动弹窗
|
|
|
=====================*/
|
|
|
.aui-picker{
|
|
|
width: 100vw;
|
|
|
height: 100vh;
|
|
|
opacity: 1;
|
|
|
position: fixed;
|
|
|
top: 0;
|
|
|
left: 0;
|
|
|
z-index: 999;
|
|
|
background-color: rgba(0,0,0,0.5);
|
|
|
/* display: none; */
|
|
|
}
|
|
|
.aui-picker.aui-picker-in{
|
|
|
-moz-animation: aui-fade-in .1s ease-out forwards;
|
|
|
-ms-animation: aui-fade-in .1s ease-out forwards;
|
|
|
-webkit-animation: aui-fade-in .1s ease-out forwards;
|
|
|
animation: aui-fade-in .1s ease-out forwards;
|
|
|
}
|
|
|
.aui-picker.aui-picker-out{
|
|
|
-moz-animation: aui-fade-out .1s ease-out forwards;
|
|
|
-ms-animation: aui-fade-out .1s ease-out forwards;
|
|
|
-webkit-animation: aui-fade-out .1s ease-out forwards;
|
|
|
animation: aui-fade-out .1s ease-out forwards;
|
|
|
}
|
|
|
.aui-picker-main{
|
|
|
width: 100vw;
|
|
|
height: 50vh;
|
|
|
background: #FFF;
|
|
|
border-radius: 15px 15px 0 0;
|
|
|
position: absolute;
|
|
|
left: 0px;
|
|
|
bottom: 0vh;
|
|
|
z-index: 999;
|
|
|
}
|
|
|
.aui-picker.aui-picker-in .aui-picker-main{
|
|
|
-moz-animation: aui-slide-up-screen .2s ease-out forwards;
|
|
|
-ms-animation: aui-slide-up-screen .2s ease-out forwards;
|
|
|
-webkit-animation: aui-slide-up-screen .2s ease-out forwards;
|
|
|
animation: aui-slide-up-screen .2s ease-out forwards;
|
|
|
}
|
|
|
.aui-picker.aui-picker-out .aui-picker-main{
|
|
|
-moz-animation: aui-slide-down-screen .2s ease-out forwards;
|
|
|
-ms-animation: aui-slide-down-screen .2s ease-out forwards;
|
|
|
-webkit-animation: aui-slide-down-screen .2s ease-out forwards;
|
|
|
animation: aui-slide-down-screen .2s ease-out forwards;
|
|
|
}
|
|
|
.aui-picker-header{
|
|
|
width: 100%;
|
|
|
min-height: 50px;
|
|
|
position: relative;
|
|
|
z-index: 999;
|
|
|
background: #F2F2F2;
|
|
|
border-radius: 15px 15px 0 0;
|
|
|
}
|
|
|
.aui-picker-header::after{
|
|
|
content: '';
|
|
|
width: 100%;
|
|
|
height: 1px;
|
|
|
background: rgba(100,100,100,.3);
|
|
|
-moz-transform: scaleY(.3);
|
|
|
-ms-transform: scaleY(.3);
|
|
|
-webkit-transform: scaleY(.3);
|
|
|
transform: scaleY(.3);
|
|
|
position: absolute;
|
|
|
left: 0;
|
|
|
bottom: 0;
|
|
|
z-index: 999;
|
|
|
}
|
|
|
.aui-picker-title{
|
|
|
line-height: 20px;
|
|
|
text-align: center;
|
|
|
font-size: 17px;
|
|
|
color: #333;
|
|
|
padding: 15px;
|
|
|
box-sizing: border-box;
|
|
|
position: absolute;
|
|
|
left: 50px;
|
|
|
right: 50px;
|
|
|
top: 0;
|
|
|
}
|
|
|
.aui-picker-close.iconfont{
|
|
|
width: 50px;
|
|
|
height: 50px;
|
|
|
line-height: 50px;
|
|
|
text-align: center;
|
|
|
font-size: 20px;
|
|
|
color: #aaa;
|
|
|
border-radius: 0 10px 0 0;
|
|
|
position: absolute;
|
|
|
right: 0;
|
|
|
top: 0;
|
|
|
}
|
|
|
.aui-picker-content{
|
|
|
width: 100%;
|
|
|
height: -webkit-calc(100% - 100px);
|
|
|
height: calc(100% - 100px);
|
|
|
}
|
|
|
.aui-picker-nav{
|
|
|
width: 100%;
|
|
|
height: 50px;
|
|
|
text-align: left;
|
|
|
padding: 0 20px;
|
|
|
margin: 0 0 1px 0;
|
|
|
justify-content: flex-start;
|
|
|
white-space: nowrap;
|
|
|
box-sizing: border-box;
|
|
|
position: relative;
|
|
|
}
|
|
|
.aui-picker-nav::after{
|
|
|
content: '';
|
|
|
width: 100%;
|
|
|
height: 1px;
|
|
|
background: rgba(100,100,100,.3);
|
|
|
-moz-transform: scaleY(.3);
|
|
|
-ms-transform: scaleY(.3);
|
|
|
-webkit-transform: scaleY(.3);
|
|
|
transform: scaleY(.3);
|
|
|
position: absolute;
|
|
|
left: 0;
|
|
|
bottom: 0;
|
|
|
z-index: 999;
|
|
|
}
|
|
|
.aui-picker-navitem{
|
|
|
width: 80px;
|
|
|
line-height: 50px;
|
|
|
font-size: 16px;
|
|
|
margin: 0 30px 0 0;
|
|
|
text-align: center;
|
|
|
display: inline-block;
|
|
|
overflow: hidden;
|
|
|
white-space: nowrap;
|
|
|
text-overflow: ellipsis;
|
|
|
}
|
|
|
.aui-picker-navitem.active{
|
|
|
color: #197DE0;
|
|
|
}
|
|
|
.aui-picker-navborder{
|
|
|
width: 40px;
|
|
|
height: 3px;
|
|
|
background: #197DE0;
|
|
|
border-radius: 5px;
|
|
|
transition: left .15s;
|
|
|
position: absolute;
|
|
|
left: 40px;
|
|
|
bottom: 0;
|
|
|
}
|
|
|
.aui-picker-lists{
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
justify-content: space-around;
|
|
|
white-space: nowrap;
|
|
|
}
|
|
|
.aui-picker-list{
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
overflow: hidden;
|
|
|
overflow-y: scroll;
|
|
|
display: none;
|
|
|
vertical-align: top;
|
|
|
}
|
|
|
.aui-picker-list.active{
|
|
|
display: inline-block;
|
|
|
}
|
|
|
.aui-picker-list-warp{
|
|
|
width: 100%;
|
|
|
height: auto;
|
|
|
box-sizing: border-box;
|
|
|
padding: 15px 0;
|
|
|
display: inline-block;
|
|
|
}
|
|
|
.aui-picker-item{
|
|
|
width: 100%;
|
|
|
height: 50px;
|
|
|
line-height: 50px;
|
|
|
padding: 0 15px;
|
|
|
box-sizing: border-box;
|
|
|
font-size: 15px;
|
|
|
color: #333;
|
|
|
position: relative;
|
|
|
}
|
|
|
.aui-picker-item.active{
|
|
|
color: #197DE0;
|
|
|
}
|
|
|
.aui-picker-item.active::after{
|
|
|
content: '✔';
|
|
|
font-size: 15px;
|
|
|
color: #197DE0;
|
|
|
position: absolute;
|
|
|
top: 0px;
|
|
|
right: 10px;
|
|
|
}
|
|
|
|
|
|
</style> |