Files
pda-cli/src/components/u-action-sheet/u-action-sheet.vue
T
2026-09-04 15:57:46 +08:00

248 lines
5.8 KiB
Vue

<template>
<u-popup mode="bottom" :border-radius="borderRadius" :popup="false" v-model="value" :maskCloseAble="maskCloseAble"
length="auto" :safeAreaInsetBottom="safeAreaInsetBottom" @close="popupClose" :z-index="uZIndex">
<view class="u-tips u-border-bottom" v-if="tips.text" :style="[tipsStyle]">
{{tips.text}}
</view>
<view class="u-action-sheet-search" v-if="showSearch" @tap.stop>
<u-icon name="search" size="32" color="#909399"></u-icon>
<input
class="u-action-sheet-search__input"
:value="keyword"
:placeholder="searchPlaceholder"
confirm-type="search"
:adjust-position="true"
@input="onSearchInput"
/>
<u-icon
v-if="keyword"
name="close-circle-fill"
size="28"
color="#c0c4cc"
@tap.stop="clearSearch"
></u-icon>
</view>
<scroll-view scroll-y class="u-action-sheet-scroll">
<view
v-for="(item, index) in displayList"
:key="item._originIndex"
@touchmove.stop.prevent
@tap="itemClick(item._originIndex)"
:style="[itemStyle(item._originIndex)]"
class="u-action-sheet-item u-line-1"
:class="[index < displayList.length - 1 ? 'u-border-bottom' : '']"
:hover-stay-time="150"
>
<text>{{item.text}}</text>
<text class="u-action-sheet-item__subtext u-line-1" v-if="item.subText">{{item.subText}}</text>
</view>
<view v-if="!displayList.length" class="u-action-sheet-empty">无匹配选项</view>
</scroll-view>
<view class="u-gab" v-if="cancelBtn">
</view>
<view @touchmove.stop.prevent class="u-actionsheet-cancel u-action-sheet-item" hover-class="u-hover-class"
:hover-stay-time="150" v-if="cancelBtn" @tap="close">{{cancelText}}</view>
</u-popup>
</template>
<script>
/**
* actionSheet 操作菜单(本地覆盖:选项支持搜索)
* @description 本组件用于从底部弹出一个操作菜单,供用户选择并返回结果。
* @tutorial https://www.uviewui.com/components/actionSheet.html
* @property {Array<Object>} list 按钮的文字数组,见官方文档示例
* @property {Boolean} show-search 是否显示搜索框(默认true)
* @property {String} search-placeholder 搜索框占位文字
* @event {Function} click 点击ActionSheet列表项时触发,返回原始列表下标
* @example <u-action-sheet :list="list" @click="click" v-model="show"></u-action-sheet>
*/
export default {
name: "u-action-sheet",
props: {
maskCloseAble: {
type: Boolean,
default: true
},
list: {
type: Array,
default () {
return [];
}
},
tips: {
type: Object,
default () {
return {
text: '',
color: '',
fontSize: '26'
}
}
},
cancelBtn: {
type: Boolean,
default: true
},
safeAreaInsetBottom: {
type: Boolean,
default: false
},
value: {
type: Boolean,
default: false
},
borderRadius: {
type: [String, Number],
default: 0
},
zIndex: {
type: [String, Number],
default: 0
},
cancelText: {
type: String,
default: '取消'
},
showSearch: {
type: Boolean,
default: true
},
searchPlaceholder: {
type: String,
default: '搜索'
}
},
data() {
return {
keyword: ''
};
},
watch: {
value(val) {
if (val) this.keyword = '';
}
},
computed: {
tipsStyle() {
let style = {};
if (this.tips.color) style.color = this.tips.color;
if (this.tips.fontSize) style.fontSize = this.tips.fontSize + 'rpx';
return style;
},
itemStyle() {
return (index) => {
let style = {};
const item = this.list[index];
if (!item) return style;
if (item.color) style.color = item.color;
if (item.fontSize) style.fontSize = item.fontSize + 'rpx';
if (item.disabled) style.color = '#c0c4cc';
return style;
}
},
uZIndex() {
return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
},
displayList() {
const keyword = (this.keyword || '').trim().toLowerCase();
return (this.list || []).reduce((arr, item, index) => {
const text = String((item && item.text) || '');
const subText = String((item && item.subText) || '');
if (!keyword || text.toLowerCase().indexOf(keyword) !== -1 || subText.toLowerCase().indexOf(keyword) !== -1) {
arr.push(Object.assign({}, item, { _originIndex: index }));
}
return arr;
}, []);
}
},
methods: {
onSearchInput(e) {
this.keyword = e && e.detail && e.detail.value != null ? e.detail.value : '';
},
clearSearch() {
this.keyword = '';
},
close() {
this.popupClose();
this.$emit('close');
},
popupClose() {
this.keyword = '';
this.$emit('input', false);
},
itemClick(index) {
if(this.list[index] && this.list[index].disabled) return;
this.$emit('click', index);
this.$emit('input', false);
}
}
}
</script>
<style lang="scss" scoped>
@import "~uview-ui/libs/css/style.components.scss";
.u-tips {
font-size: 26rpx;
text-align: center;
padding: 34rpx 0;
line-height: 1;
color: $u-tips-color;
}
.u-action-sheet-search {
@include vue-flex;
align-items: center;
margin: 16rpx 24rpx;
padding: 0 24rpx;
height: 80rpx;
background-color: #f5f5f5;
border-radius: 12rpx;
box-sizing: border-box;
&__input {
flex: 1;
height: 80rpx;
margin-left: 12rpx;
font-size: 30rpx;
color: #303133;
}
}
.u-action-sheet-scroll {
max-height: 600rpx;
}
.u-action-sheet-empty {
text-align: center;
padding: 60rpx 0;
font-size: 30rpx;
color: #909399;
}
.u-action-sheet-item {
@include vue-flex;
line-height: 1;
justify-content: center;
align-items: center;
font-size: 32rpx;
padding: 34rpx 0;
flex-direction: column;
}
.u-action-sheet-item__subtext {
font-size: 24rpx;
color: $u-tips-color;
margin-top: 20rpx;
}
.u-gab {
height: 12rpx;
background-color: rgb(234, 234, 236);
}
.u-actionsheet-cancel {
color: $u-main-color;
}
</style>