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

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<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>