This commit is contained in:
那些花儿
2025-04-30 17:11:54 +08:00
parent d8ab956b5d
commit db01594729
3 changed files with 242 additions and 11 deletions
+231
View File
@@ -0,0 +1,231 @@
<template>
<view class="search-picker">
<view class="picker-field" @click="openPicker">
<input
@click="openPicker"
class="picker-input"
:value="getSelectedLabel()"
:placeholder="placeholder"
:readonly="true"
:disabled="true"
/>
<text class="arrow" :class="{ 'arrow-up': isPickerOpen }">›</text>
</view>
<view v-if="isPickerOpen" class="dropdown-container">
<!-- 搜索框 -->
<view class="search-container">
<input
class="search-input"
v-model="searchText"
placeholder="搜索"
confirm-type="search"
@input="onSearch"
auto-focus
/>
</view>
<scroll-view
:scroll-y="true"
class="options-list"
:style="{ maxHeight: maxHeight + 'rpx' }"
>
<view
v-for="(item, index) in filteredOptions"
:key="index"
class="option-item"
:class="{ 'option-selected': isSelected(item) }"
@tap="selectOption(item)"
>
{{ item.label }}
</view>
<view v-if="filteredOptions.length === 0" class="no-data">
没有找到匹配结果
</view>
</scroll-view>
</view>
<!-- 遮罩层,点击关闭下拉框 -->
<view v-if="isPickerOpen" class="mask" @tap="closePicker"></view>
</view>
</template>
<script setup>
import { ref, computed, watch } from 'vue';
const props = defineProps({
// 选项数据,格式为 [{value: '1', label: '选项1'}, {value: '2', label: '选项2'}]
options: {
type: Array,
default: () => []
},
// 当前选中的值
modelValue: {
type: [String, Number, Object],
default: ''
},
// 占位文字
placeholder: {
type: String,
default: '请选择'
},
// 选项列表最大高度(单位rpx)
maxHeight: {
type: Number,
default: 500
}
});
// Emits 定义
const emit = defineEmits(['update:modelValue', 'change']);
// 响应式状态
const isPickerOpen = ref(false);
const searchText = ref('');
const selectedValue = ref(props.modelValue);
// 监听modelValue变化
watch(() => props.modelValue, (newVal) => {
selectedValue.value = newVal;
});
// 根据搜索文本过滤选项
const filteredOptions = computed(() => {
if (!searchText.value) {
return props.options;
}
return props.options.filter(item =>
item.label.toLowerCase().includes(searchText.value.toLowerCase())
);
});
// 打开选择器
const openPicker = () => {
debugger
searchText.value = '';
isPickerOpen.value = true;
};
// 关闭选择器
const closePicker = () => {
isPickerOpen.value = false;
};
// 选择选项
const selectOption = (item) => {
selectedValue.value = item.value;
emit('update:modelValue', item.value);
emit('change', item.value);
closePicker();
};
// 判断选项是否被选中
const isSelected = (item) => {
return item.value === selectedValue.value;
};
// 搜索处理
const onSearch = () => {
// 搜索逻辑已通过计算属性 filteredOptions 实现
};
// 获取选中项的标签
const getSelectedLabel = () => {
const selected = props.options.find(item => item.value === selectedValue.value);
return selected ? selected.label : '';
};
</script>
<style scoped lang="less">
.search-picker {
position: relative;
//height: 100rpx;
background-color: #fff;
border-radius: 16rpx;
//padding: 0 30rpx;
display: flex;
align-items: center;
justify-content: space-between;
//box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.03);
z-index: 100;
width: 100%;
}
.picker-field {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
}
.picker-input {
flex: 1;
//height: 80rpx;
font-size: 28rpx;
}
.arrow {
font-size: 36rpx;
color: #999;
transform: rotate(90deg);
}
.arrow-up {
transform: rotate(180deg);
}
.dropdown-container {
position: absolute;
top: 110rpx; /* 输入框下方留出一点间距 */
left: 0;
width: 100%;
background-color: #fff;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
z-index: 101;
}
.search-container {
padding: 20rpx;
border-bottom: 1px solid #f5f5f5;
}
.search-input {
height: 80rpx;
border-radius: 40rpx;
background-color: #f7f7f7;
padding: 0 30rpx;
font-size: 28rpx;
}
.options-list {
width: 100%;
}
.option-item {
padding: 24rpx 30rpx;
font-size: 28rpx;
border-bottom: 1px solid #f5f5f5;
}
.option-selected {
color: #5c6bc0;
background-color: #f7f7f7;
}
.no-data {
padding: 40rpx 0;
text-align: center;
color: #999;
font-size: 28rpx;
}
.mask {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 99;
}
</style>
@@ -4,21 +4,21 @@
<view class="success-content">
<!-- 成功图片 -->
<view class="success-image">
<image src="https://cdn-icons-png.flaticon.com/512/10613/10613684.png" mode="aspectFit"></image>
<image src="/static/img/successful.png" mode="aspectFit"></image>
</view>
<!-- 成功信息 -->
<view class="success-info">
<view class="success-title">报名成功</view>
<view class="success-subtitle">您已成功报名参加"{{ activityTitle }}"</view>
</view>
<!-- 小提示 -->
<view class="success-tips">
<t-icon name="info-circle-filled" size="16px" />
<text>活动开始前我们将通过短信通知您</text>
</view>
<!-- 底部按钮 -->
<view class="action-buttons">
<t-button theme="default" shape="round" @click="navigateToHome">返回首页</t-button>
@@ -102,7 +102,7 @@ const viewRegistrationDetails = () => {
margin-bottom: 30px;
width: 200px;
height: 200px;
image {
width: 100%;
height: 100%;
@@ -151,12 +151,12 @@ const viewRegistrationDetails = () => {
padding: 10px 20px;
margin-top: 20px;
margin-bottom: 40px;
.t-icon {
color: #ff5f5c;
margin-right: 6px;
}
text {
color: #666;
font-size: 14px;
@@ -170,19 +170,19 @@ const viewRegistrationDetails = () => {
width: 100%;
padding: 0 20px;
margin-top: 20px;
:deep(.t-button) {
flex: 1;
}
:deep(.t-button--primary) {
background-color: #ff5f5c !important;
border-color: #ff5f5c !important;
}
:deep(.t-button--default) {
border-color: #ff5f5c !important;
color: #ff5f5c !important;
}
}
</style>
</style>
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB