248 lines
5.8 KiB
Vue
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>
|