click suffix icon to show options
This commit is contained in:
@ -1,17 +1,9 @@
|
||||
<script setup>
|
||||
import {
|
||||
nextTick,
|
||||
onMounted,
|
||||
onUnmounted,
|
||||
ref,
|
||||
toRefs,
|
||||
watch,
|
||||
watchEffect,
|
||||
} from "vue";
|
||||
import {nextTick, onMounted, onUnmounted, ref, toRefs, watch, watchEffect,} from "vue";
|
||||
import InfiniteLoading from "v3-infinite-loading";
|
||||
import "v3-infinite-loading/lib/style.css";
|
||||
import { debounce } from "lodash-es"; //required if you're not going to override default slots
|
||||
import { ElInput, ElPopover, ElScrollbar } from "element-plus";
|
||||
import {debounce} from "lodash-es"; //required if you're not going to override default slots
|
||||
import {ElInput, ElPopover, ElScrollbar} from "element-plus";
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {},
|
||||
@ -25,7 +17,7 @@ const props = defineProps({
|
||||
width: {
|
||||
type: Number,
|
||||
},
|
||||
prefixIcon: { type: String },
|
||||
prefixIcon: {type: String},
|
||||
query: {
|
||||
type: Object,
|
||||
required: true,
|
||||
@ -43,13 +35,14 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
|
||||
const { modelValue } = toRefs(props);
|
||||
const {modelValue} = toRefs(props);
|
||||
const loadKey = ref(0);
|
||||
const emit = defineEmits(["update:modelValue", "change", "confirm"]);
|
||||
|
||||
const showPopOver = ref(false);
|
||||
|
||||
const inputRefWhenShowPop = ref();
|
||||
const inputRefWhenNotShowPop = ref()
|
||||
const placeholderWhenShowPop = ref("");
|
||||
const placeholderWhenNotShowPop = ref("");
|
||||
const optionLabelWhenShowPop = ref("");
|
||||
@ -57,43 +50,43 @@ const optionLabelWhenNotShowPop = ref("");
|
||||
const echoLabel = ref("");
|
||||
const options = ref([]);
|
||||
const page = ref(0);
|
||||
|
||||
const initOptions = (keyword) => {
|
||||
props
|
||||
.remoteMethod({
|
||||
[props.query.page]: page.value,
|
||||
[props.query.size]: 10,
|
||||
[props.query.searchKey]: keyword,
|
||||
})
|
||||
.then((rows) => {
|
||||
options.value = rows;
|
||||
});
|
||||
.remoteMethod({
|
||||
[props.query.page]: page.value,
|
||||
[props.query.size]: 10,
|
||||
[props.query.searchKey]: keyword,
|
||||
})
|
||||
.then((rows) => {
|
||||
options.value = rows;
|
||||
});
|
||||
};
|
||||
|
||||
const loadMore = async ($state) => {
|
||||
page.value++;
|
||||
props
|
||||
.remoteMethod({
|
||||
[props.query.page]: page.value,
|
||||
[props.query.size]: 10,
|
||||
[props.query.searchKey]: showPopOver.value
|
||||
? optionLabelWhenShowPop.value ?? null
|
||||
: null,
|
||||
})
|
||||
.then((rows) => {
|
||||
options.value.push(...rows);
|
||||
if (rows.length < 10) {
|
||||
$state.complete();
|
||||
} else {
|
||||
$state.loaded();
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
$state.error();
|
||||
});
|
||||
.remoteMethod({
|
||||
[props.query.page]: page.value,
|
||||
[props.query.size]: 10,
|
||||
[props.query.searchKey]: showPopOver.value
|
||||
? optionLabelWhenShowPop.value ?? null
|
||||
: null,
|
||||
})
|
||||
.then((rows) => {
|
||||
options.value.push(...rows);
|
||||
if (rows.length < 10) {
|
||||
$state.complete();
|
||||
} else {
|
||||
$state.loaded();
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
$state.error();
|
||||
});
|
||||
};
|
||||
|
||||
const handleInputClick = () => {
|
||||
const handleInputClick = (event) => {
|
||||
event.stopPropagation()
|
||||
showPopOver.value = true;
|
||||
placeholderWhenShowPop.value = optionLabelWhenNotShowPop.value;
|
||||
nextTick(() => {
|
||||
@ -143,12 +136,12 @@ watchEffect(() => {
|
||||
if (showPopOver.value) return;
|
||||
if (modelValue.value) {
|
||||
optionLabelWhenNotShowPop.value =
|
||||
options.value.find((el) => el[props.prop.value] === modelValue.value)?.[
|
||||
props.prop.label
|
||||
] ??
|
||||
echoLabel.value ??
|
||||
props.defaultLabel ??
|
||||
"...";
|
||||
options.value.find((el) => el[props.prop.value] === modelValue.value)?.[
|
||||
props.prop.label
|
||||
] ??
|
||||
(echoLabel.value.length ? echoLabel.value : null) ??
|
||||
props.defaultLabel ??
|
||||
"...";
|
||||
} else {
|
||||
optionLabelWhenNotShowPop.value = "";
|
||||
placeholderWhenNotShowPop.value = props.placeholder;
|
||||
@ -159,6 +152,7 @@ watch(modelValue, (value) => {
|
||||
emit("change", value);
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* 点击空白关闭弹出选项列表
|
||||
* @param event
|
||||
@ -179,6 +173,17 @@ onMounted(() => {
|
||||
page.value++;
|
||||
initOptions();
|
||||
document.body.addEventListener("click", handleBodyClick);
|
||||
watch(showPopOver, (show) => {
|
||||
if (show) {
|
||||
inputRefWhenNotShowPop.value?.input?.parentNode?.removeEventListener('click', handleInputClick)
|
||||
} else {
|
||||
nextTick(() => {
|
||||
inputRefWhenNotShowPop.value?.input?.parentNode?.addEventListener('click', handleInputClick)
|
||||
})
|
||||
|
||||
}
|
||||
}, {immediate: true})
|
||||
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
@ -188,48 +193,48 @@ onUnmounted(() => {
|
||||
|
||||
<template>
|
||||
<el-popover
|
||||
:popper-style="{
|
||||
:popper-style="{
|
||||
padding: 0,
|
||||
}"
|
||||
:visible="showPopOver"
|
||||
:width="width ?? 240"
|
||||
placement="bottom"
|
||||
:visible="showPopOver"
|
||||
:width="width ?? 240"
|
||||
placement="bottom"
|
||||
>
|
||||
<template #reference>
|
||||
<div :style="`width: ${width ?? 240}px`">
|
||||
<!--选项显示时-->
|
||||
<el-input
|
||||
v-if="showPopOver"
|
||||
ref="inputRefWhenShowPop"
|
||||
v-model="optionLabelWhenShowPop"
|
||||
:placeholder="placeholderWhenShowPop"
|
||||
:prefix-icon="prefixIcon"
|
||||
:size="size ?? 'default'"
|
||||
class="select-inner"
|
||||
suffix-icon="ArrowUp"
|
||||
@input="handleInputChange"
|
||||
@click.stop
|
||||
v-if="showPopOver"
|
||||
ref="inputRefWhenShowPop"
|
||||
v-model="optionLabelWhenShowPop"
|
||||
:placeholder="placeholderWhenShowPop"
|
||||
:prefix-icon="prefixIcon"
|
||||
:size="size ?? 'default'"
|
||||
class="select-inner"
|
||||
suffix-icon="ArrowUp"
|
||||
@input="handleInputChange"
|
||||
@click.stop
|
||||
>
|
||||
<template #prefix>
|
||||
<slot name="prefix" />
|
||||
<slot name="prefix"/>
|
||||
</template>
|
||||
</el-input>
|
||||
<!--选项隐藏时-->
|
||||
<el-input
|
||||
v-else
|
||||
v-model="optionLabelWhenNotShowPop"
|
||||
:placeholder="placeholderWhenNotShowPop"
|
||||
:prefix-icon="prefixIcon"
|
||||
:size="size ?? 'default'"
|
||||
class="select-inner"
|
||||
clearable
|
||||
suffix-icon="ArrowDown"
|
||||
@clear="handleClearSeletion"
|
||||
@click.stop="handleInputClick"
|
||||
v-else
|
||||
ref="inputRefWhenNotShowPop"
|
||||
v-model="optionLabelWhenNotShowPop"
|
||||
:placeholder="placeholderWhenNotShowPop"
|
||||
:prefix-icon="prefixIcon"
|
||||
:size="size ?? 'default'"
|
||||
class="select-inner"
|
||||
clearable
|
||||
suffix-icon="ArrowDown"
|
||||
@clear="handleClearSeletion"
|
||||
>
|
||||
<!-- @blur="handleInputBlur"-->
|
||||
<!-- @click.stop="handleFocus"-->
|
||||
<template #prefix>
|
||||
<slot name="prefix" />
|
||||
<slot name="prefix"/>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
@ -237,12 +242,12 @@ onUnmounted(() => {
|
||||
<el-scrollbar class="options-wrap" height="260" @click.stop>
|
||||
<ul class="options">
|
||||
<li
|
||||
v-for="option in options"
|
||||
:key="option[prop.value]"
|
||||
:class="`option-item ${
|
||||
v-for="option in options"
|
||||
:key="option[prop.value]"
|
||||
:class="`option-item ${
|
||||
option[prop.value] === modelValue ? 'selected' : null
|
||||
}`"
|
||||
@click.stop="selectOption(option)"
|
||||
@click.stop="selectOption(option)"
|
||||
>
|
||||
{{ option[prop.label] }}
|
||||
</li>
|
||||
@ -253,7 +258,7 @@ onUnmounted(() => {
|
||||
</template>
|
||||
<template #complete>
|
||||
<div
|
||||
style="display: flex; justify-content: center; align-items: center"
|
||||
style="display: flex; justify-content: center; align-items: center"
|
||||
>
|
||||
-
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user