You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

242 lines
6.2 KiB

<template>
<view class="uv-drop-down-popup">
<uv-transition :show="show" mode="fade" :duration="300" :custom-style="overlayStyle" @click="clickOverlay">
<view class="uv-dp__container" ref="uvDPContainer" :style="{height: `${height}px`}" @click.stop="blockClick">
<view class="uv-dp__container__list" ref="uvDPList">
<slot>
<view class="uv-dp__container__list--item" v-for="(item,index) in list" :key="index" @click="clickHandler(item,index)" :style="[itemCustomStyle(index)]">
<uv-text :text="item[keyName]" :size="getTextSize(index)" :color="getTextColor(index)"></uv-text>
</view>
</slot>
</view>
</view>
</uv-transition>
</view>
</template>
<script>
import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js';
import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js';
// #ifdef APP-NVUE
const animation = uni.requireNativePlugin('animation');
const dom = uni.requireNativePlugin('dom');
// #endif
/**
* DropDownPopup 下拉框
* @description 下拉筛选框
* @tutorial https://ext.dcloud.net.cn/plugin?name=uv-drop-down
* @property {String | Number} name 字段标识
* @property {String | Number} zIndex 弹出层的层级
* @property {String | Number} opacity 遮罩层的透明度
* @property {Boolean} clickOverlayOnClose 是否允许点击遮罩层关闭弹窗
* @property {Object} currentDropItem 当前下拉筛选菜单对象
* @property {String} keyName 指定从当前下拉筛选菜单对象元素中读取哪个属性作为文本展示
*/
export default {
name: 'uv-drop-down-popup',
mixins: [mpMixin, mixin],
props: {
sign: {
type: [String, Number],
default: 'UVDROPDOWN'
},
zIndex: {
type: [Number, String],
default: 999
},
opacity: {
type: [Number, String],
default: 0.5
},
clickOverlayOnClose: {
type: Boolean,
default: true
},
// 当前下拉选项对象
currentDropItem: {
type: Object,
default () {
return {
activeIndex: 0,
child: []
}
}
},
keyName: {
type: String,
default: 'label'
}
},
data() {
return {
show: false,
rect: {},
height: 0
}
},
computed: {
overlayStyle() {
let { height = 0, top = 0 } = this.rect;
// #ifdef H5
top += this.$uv.sys().windowTop;
// #endif
const style = {
position: 'fixed',
top: `${top+height}px`,
left: 0,
right: 0,
zIndex: this.zIndex,
bottom: 0,
'background-color': `rgba(0, 0, 0, ${this.opacity})`
}
return this.$uv.deepMerge(style, this.$uv.addStyle(this.customStyle))
},
list() {
try {
return Array.isArray(this.currentDropItem.child) ? this.currentDropItem.child : [];
} catch (e) {
return [];
}
},
getTextColor(index) {
return index => {
const active = this.currentDropItem.activeIndex == index;
const color = this.currentDropItem.color;
const activeColor = this.currentDropItem.activeColor;
if (active) {
return activeColor ? activeColor : '#3c9cff';
}
return color ? color : '#333';
}
},
getTextSize(index) {
return index => {
const active = this.currentDropItem.activeIndex == index;
const size = this.currentDropItem.size;
const activeSize = this.currentDropItem.activeSize;
if (active) {
return activeSize ? activeSize : '30rpx';
}
return size ? size : '30rpx';
}
},
itemCustomStyle() {
return index => {
const active = this.currentDropItem.activeIndex == index;
const style = {};
if (active && this.currentDropItem.itemActiveCustomStyle) {
return this.$uv.deepMerge(style, this.$uv.addStyle(this.currentDropItem.itemActiveCustomStyle));
}
if (this.currentDropItem.itemCustomStyle) {
return this.$uv.deepMerge(style, this.$uv.addStyle(this.currentDropItem.itemCustomStyle))
}
return style;
}
}
},
created() {
this.init();
},
methods: {
blockClick() {},
clickHandler(item, index) {
this.currentDropItem.activeIndex = index;
this.$emit('clickItem', item);
this.close();
},
init() {
uni.$off(`${this.sign}_GETRECT`);
uni.$on(`${this.sign}_GETRECT`, rect => {
this.rect = rect;
})
uni.$off(`${this.sign}_CLICKMENU`);
uni.$on(`${this.sign}_CLICKMENU`, async res => {
if (res.show) {
this.open();
} else {
this.close();
}
})
},
open() {
this.show = true;
this.$nextTick(async () => {
// #ifndef H5 || MP-WEIXIN
await this.$uv.sleep(60);
// #endif
const res = await this.queryRect();
// #ifndef APP-NVUE
this.height = res.height;
// #endif
// #ifdef APP-NVUE
this.animation(res.height);
// #endif
this.$emit('popupChange', { show: true });
})
},
close() {
if(!this.show) return;
this.height = 0;
// #ifndef APP-NVUE
this.height = 0;
// #endif
// #ifdef APP-NVUE
this.animation(0);
// #endif
this.show = false;
uni.$emit(`${this.sign}_CLOSEPOPUP`);
this.$emit('popupChange', { show: false });
},
clickOverlay() {
if (this.clickOverlayOnClose) {
this.close();
}
},
// 查询内容高度
queryRect() {
// #ifndef APP-NVUE
// 组件内部一般用this.$uvGetRect对外的为getRect二者功能一致名称不同
return new Promise(resolve => {
this.$uvGetRect(`.uv-dp__container__list`).then(size => {
resolve(size)
})
})
// #endif
// #ifdef APP-NVUE
// nvue下使用dom模块查询元素高度
// 返回一个promise让调用此方法的主体能使用then回调
return new Promise(resolve => {
dom.getComponentRect(this.$refs.uvDPList, res => {
resolve(res.size)
})
})
// #endif
},
// nvue下设置高度
animation(height, duration = 200) {
// #ifdef APP-NVUE
const ref = this.$refs['uvDPContainer'];
animation.transition(ref, {
styles: {
height: `${height}px`
},
duration
})
// #endif
}
}
}
</script>
<style scoped lang="scss">
.uv-dp__container {
/* #ifndef APP-NVUE */
overflow: hidden;
transition: all .15s;
/* #endif */
background-color: #fff;
}
.uv-dp__container__list {
&--item {
padding: 20rpx 60rpx;
}
}
</style>