feat: 新增输入框下拉组件

This commit is contained in:
nightdays 2025-11-14 16:43:44 +08:00
parent 2ebeb4376d
commit acdaabe203
2 changed files with 188 additions and 9 deletions

View File

@ -0,0 +1,172 @@
<template>
<div class="input-selet-comp" ref="inputSelectRef">
<div class="input-wrapper" :class="{ 'is-active': active }">
<div v-if="modelValue == null || modelValue === ''" class="placeholder">{{ placeholder }}</div>
<input :value="modelValue" ref="innerInputRef" class="inner-input" @click="show" @blur="deferClose"
@input="input" />
</div>
</div>
<div class="input-selet-options-popup" ref="popupRef" :style="optionsWrapperStyle"
v-if="options && options.length > 0">
<div class="options-wrapper">
<div class="option" v-for="(option, index) in options" :key="index" @click="changeValue(option)" :class="{'is-select' : option.value == modelValue }">
{{ option.label }}
</div>
</div>
</div>
</template>
<script setup>
import { onMounted, ref } from 'vue';
const props = defineProps({
options: {
type: Array,
default: () => []
},
placeholder: {
type: String,
default: ''
},
modelValue: {
}
})
const emit = defineEmits(['update:modelValue']);
const optionsWrapperStyle = ref({})
const inputSelectRef = ref(null)
const innerInputRef = ref(null)
const popupRef = ref(null)
const active = ref(false)
const show = () => {
if (props.options && props.options.length > 0) {
const rect = inputSelectRef.value.getBoundingClientRect();
optionsWrapperStyle.value = {
left: rect.left + 'px',
top: rect.bottom + 'px',
transform: 'scaleY(1)',
width: rect.width + 'px',
}
const popupRect = popupRef.value.getBoundingClientRect();
//
if (rect.right + popupRect.width / 2 > window.innerWidth) {
optionsWrapperStyle.value.left = rect.right - popupRect.width + 'px';
}
active.value = true
}
}
const deferClose = () => {
setTimeout(() => {
close()
}, 100)
}
const close = () => {
if (props.options && props.options.length > 0) {
optionsWrapperStyle.value.transform = 'scaleY(0)';
}
active.value = false
}
const input = (event) => {
emit("update:modelValue", event.target.value)
}
const changeValue = (option) => {
emit("update:modelValue", option.value)
}
</script>
<style scoped lang="scss">
.input-selet-comp {
width: 100%;
.input-wrapper {
position: relative;
background-color: var(--el-input-bg-color, var(--el-fill-color-blank));
background-image: none;
border-radius: var(--el-input-border-radius, var(--el-border-radius-base));
box-shadow: 0 0 0 1px var(--el-input-border-color, var(--el-border-color)) inset;
padding: 1px 11px;
transform: translateZ(0);
transition: var(--el-transition-box-shadow);
&:hover {
box-shadow: 0 0 0 1px #c0c4cc inset;
}
&.is-active {
box-shadow: 0 0 0 1px #409eff inset;
}
}
.placeholder {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
pointer-events: none;
padding: 1px 11px;
color: var(--el-text-color-placeholder);
}
.inner-input {
width: 100%;
outline: none;
border: none;
background: transparent;
padding: 0;
margin: 0;
}
}
.input-selet-options-popup {
position: fixed;
display: flex;
flex-direction: column;
margin: 0;
z-index: 10;
transform: scaleY(0);
transform-origin: center top;
transition: transform 0.2s;
&::before {
content: '';
display: inline-block;
height: 5px;
}
.options-wrapper {
display: flex;
flex-direction: column;
border-radius: 4px;
padding: 6px 0;
background: var(--el-bg-color-overlay);
border: 1px solid var(--el-border-color-light);
box-shadow: var(--el-box-shadow-light);
}
.option {
border-radius: 4px;
transition: background-color 0.2s;
white-space: nowrap;
color: var(--el-text-color-regular);
cursor: pointer;
font-size: var(--el-font-size-base);
height: 34px;
line-height: 34px;
overflow: hidden;
padding: 0 32px 0 20px;
&.is-select {
color: #409eff;
}
}
}
</style>

View File

@ -13,18 +13,12 @@
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="设备大类" prop="sbdl"> <el-form-item label="设备大类" prop="sbdl">
<el-select v-model="form.sbdl" placeholder="请选择"> <InputSelect v-model="form.sbdl" placeholder="请选择" :options="options['sbdl']" />
<el-option label="示例大类1" value="dl1" />
<el-option label="示例大类2" value="dl2" />
</el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="设备类型" prop="sblx"> <el-form-item label="设备类型" prop="sblx">
<el-select v-model="form.sblx" placeholder="请选择"> <InputSelect v-model="form.sblx" placeholder="请选择" :options="options['sblx']" />
<el-option label="示例类型1" value="lx1" />
<el-option label="示例类型2" value="lx2" />
</el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -57,7 +51,7 @@
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="购买费用(万元)" prop="gmfy"> <el-form-item label="购买费用(万元)" prop="gmfy">
<el-input-number v-model="form.gmfy" :min="1" :max="10" controls-position="right" /> <el-input-number v-model="form.gmfy" :min="0" controls-position="right" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
@ -98,6 +92,7 @@
<script setup> <script setup>
import { ref, computed } from "vue"; import { ref, computed } from "vue";
import InputSelect from "@/component/InputSelect/InputSelect.vue";
const props = defineProps({ const props = defineProps({
detailData: { detailData: {
@ -115,6 +110,18 @@ const props = defineProps({
} }
}); });
const options = ref({
'sbdl': [
{ label: "示例大类1", value: "示例大类1" },
{ label: "示例大类2", value: "示例大类2" },
],
"sblx": [
{ label: "示例类型1", value: "示例类型1" },
{ label: "示例类型2", value: "示例类型2" },
]
})
const stationName = computed(() => { const stationName = computed(() => {
return props.yhzData ? props.yhzData.rawName : '' return props.yhzData ? props.yhzData.rawName : ''
}) })