| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- <template>
- <view class="w-full" @click="handleClick">
- <view class="flex items-center gap-x-10" :style="customStyle">
- <view v-if="matchValue" class="flex-1 text-fore-title" :style="getValueStyle"
- :class="{ 'text-[#c0c4cc]': disabled || readonly }">
- <slot :label="label">
- {{ label }}
- </slot>
- </view>
- <view v-else class="flex-1 text-[#c0c4cc]" :style="getPlaceholderStyle">{{ placeholder }}</view>
- <view v-if="!readonly" class="transition-all duration-300">
- <uv-icon :name="icon" size="15" color="#B3B3B3" />
- </view>
- </view>
- </view>
- <root-portal>
- <uv-picker ref="pickerRef" :showToolbar="false" :columns="columns" :defaultIndex="defaultIndex" :round="16"
- activeColor="#31A0FC" :keyName="keyLabel" :title="title" @change="handleChange" @close="onClose">
- <template #toolbar>
- <view class="flex items-center justify-between pt-20">
- <view class="px-46 py-20 text-28 text-fore-light" @click="handleCancel">取消</view>
- <text class="text-30 text-fore-title font-bold">{{ title }}</text>
- <view class="px-46 py-20 text-28 text-fore-title" @click="handleConfirm">确认</view>
- </view>
- </template>
- </uv-picker>
- </root-portal>
- </template>
- <script lang="ts" setup>
- const modelValue = defineModel<string | number>('modelValue', {
- default: ''
- });
- const props = defineProps({
- placeholder: {
- type: String,
- default: '请选择',
- },
- title: {
- type: String,
- default: '',
- },
- icon: {
- type: String,
- default: 'arrow-right',
- },
- list: {
- type: Array as PropType<any[]>,
- default: () => [],
- },
- keyLabel: {
- type: String,
- default: 'label',
- },
- keyValue: {
- type: String,
- default: 'value',
- },
- disabled: {
- type: Boolean,
- default: false,
- },
- readonly: {
- type: Boolean,
- default: false,
- },
- customStyle: {
- type: Object,
- default: () => ({}),
- },
- placeholderStyle: {
- type: Object,
- default: () => ({}),
- },
- fontSize: {
- type: Number,
- default: 30,
- }
- });
- const defaultIndex = ref([0]);
- const label = ref('');
- const isOpen = ref(false);
- const matchValue = ref(false);
- const columns = computed(() => {
- return [props.list];
- });
- const getPlaceholderStyle = computed(() => {
- return {
- ...props.placeholderStyle,
- fontSize: props.fontSize + 'rpx'
- }
- });
- const getValueStyle = computed(() => {
- return {
- fontSize: props.fontSize + 'rpx'
- }
- });
- const init = () => {
- if (modelValue.value !== null && modelValue.value !== undefined && modelValue.value !== '') {
- const index = props.list.findIndex(item => item[props.keyValue] == modelValue.value);
- if (index !== -1) {
- defaultIndex.value = [index];
- label.value = props.list[index][props.keyLabel];
- matchValue.value = true;
- } else {
- // 如果找不到匹配项,重置状态
- defaultIndex.value = [0];
- label.value = props.placeholder;
- matchValue.value = false;
- }
- } else {
- defaultIndex.value = [0];
- label.value = props.placeholder;
- matchValue.value = false;
- }
- }
- // 使用 watch 替代 watchEffect,避免循环更新
- watch([() => modelValue.value, () => props.list], init, { immediate: true });
- const pickerRef = ref();
- const emit = defineEmits<{
- (e: 'change', value: number, selectedItem: any): void;
- (e: 'click'): void;
- }>();
- const handleConfirm = () => {
- const { value } = pickerRef.value.manualConfirm();
- const oldValue = modelValue.value;
- const newValue = value[0][props.keyValue];
- // 更新 modelValue
- modelValue.value = newValue;
- // 手动更新显示状态,确保界面同步
- const selectedItem = value[0];
- label.value = selectedItem[props.keyLabel];
- matchValue.value = true;
- // 发出 change 事件
- if (oldValue !== newValue) {
- emit('change', newValue, selectedItem);
- }
- pickerRef.value.close();
- }
- const handleCancel = () => {
- pickerRef.value.close();
- }
- const handleChange = () => { }
- const handleClick = () => {
- emit('click');
- if (props.disabled) {
- return;
- }
- init();
- isOpen.value = true;
- pickerRef.value.open();
- }
- const onClose = () => {
- isOpen.value = false;
- }
- </script>
- <style lang="scss" scoped></style>
|