layui/.svn/pristine/94/94867b07ab10454d6df0d33e920ca94a7354d732.svn-base
2022-12-09 16:41:41 +08:00

268 lines
6.6 KiB
Plaintext

<script lang="ts">
export default {
name: "LaySelect",
};
</script>
<script setup lang="ts">
import "./index.less";
import {
provide,
computed,
ref,
Ref,
useSlots,
onMounted,
VNode,
Component,
watch,
onUnmounted,
StyleValue,
} from "vue";
import { LayIcon } from "@layui/icons-vue";
import LayInput from "../input/index.vue";
import LayTagInput from "../tagInput/index.vue";
import LayDropdown from "../dropdown/index.vue";
import LaySelectOption, { SelectOptionProps } from "../selectOption/index.vue";
import { SelectSize } from "./interface";
export interface SelectProps {
name?: string;
disabled?: boolean;
placeholder?: string;
searchPlaceholder?: string;
modelValue?: any;
multiple?: boolean;
items?: SelectOptionProps[];
size?: SelectSize;
collapseTagsTooltip?: boolean;
minCollapsedNum?: number;
allowClear?: boolean;
showSearch?: boolean;
contentClass?: string | Array<string | object> | object;
contentStyle?: StyleValue;
}
export interface SelectEmits {
(e: "update:modelValue", value: string): void;
(e: "change", value: string): void;
(e: "search", value: string): void;
}
const props = withDefaults(defineProps<SelectProps>(), {
modelValue: null,
collapseTagsTooltip: true,
minCollapsedNum: 3,
allowClear: false,
showSearch: false,
disabled: false,
multiple: false,
size: "md",
});
const slots = useSlots();
const selectRef = ref();
const searchValue = ref("");
const singleValue = ref("");
const multipleValue = ref([]);
const emits = defineEmits<SelectEmits>();
const openState: Ref<boolean> = ref(false);
const options = ref<any>([]);
const composing = ref(false);
var timer: any;
const getOption = (nodes: VNode[], newOptions: any[]) => {
nodes?.map((item) => {
let component = item.type as Component;
if (item.type.toString() == "Symbol(Fragment)") {
getOption(item.children as VNode[], newOptions);
} else {
if (component.name == LaySelectOption.name) {
if (item.children) {
// @ts-ignore
const label = item.children.default()[0].children;
if (typeof label == "string") {
// @ts-ignore
item.props.label = label;
}
}
newOptions.push(item.props);
}
}
});
};
const intOption = () => {
const newOptions: any[] = [];
if (slots.default) {
getOption(slots.default(), newOptions);
}
Object.assign(newOptions, props.items);
if (JSON.stringify(newOptions) != JSON.stringify(options.value)) {
options.value = newOptions;
}
};
const handleRemove = (value: any) => {
if (Array.isArray(selectedValue.value)) {
selectedValue.value = selectedValue.value.filter((item) => item != value);
}
};
const onCompositionstart = () => {
composing.value = true;
};
const onCompositionend = (event: Event) => {
composing.value = false;
handleSearch((event.target as HTMLInputElement).value);
};
onMounted(() => {
intOption();
timer = setInterval(intOption, 500);
watch(
[selectedValue, options],
() => {
if (multiple.value) {
multipleValue.value = selectedValue.value?.map((value: any) => {
return options.value.find((item: any) => {
item.disabled == "" || item.disabled == true
? (item.closable = false)
: (item.closable = true);
return item.value === value;
});
});
} else {
searchValue.value = "";
singleValue.value = options.value.find((item: any) => {
return item.value === selectedValue.value;
})?.label;
}
},
{ immediate: true, deep: true }
);
});
onUnmounted(() => {
clearInterval(timer);
});
const selectedValue = computed({
get() {
return props.modelValue;
},
set(value) {
emits("update:modelValue", value);
emits("change", value);
},
});
const multiple = computed(() => {
return props.multiple;
});
const handleSearch = (value: string) => {
if (composing.value) return;
emits("search", value);
searchValue.value = value;
};
const handleClear = () => {
if (multiple.value) {
selectedValue.value = [];
} else {
selectedValue.value = "";
}
};
provide("selectRef", selectRef);
provide("openState", openState);
provide("selectedValue", selectedValue);
provide("searchValue", searchValue);
provide("multiple", multiple);
</script>
<template>
<div class="layui-select">
<lay-dropdown
ref="selectRef"
:disabled="disabled"
:contentClass="contentClass"
:contentStyle="contentStyle"
:update-at-scroll="true"
:autoFitWidth="true"
@hide="openState = false"
@show="openState = true"
>
<lay-tag-input
v-if="multiple"
v-model="multipleValue"
:allow-clear="allowClear"
:placeholder="placeholder"
:collapseTagsTooltip="collapseTagsTooltip"
:minCollapsedNum="minCollapsedNum"
:disabledInput="true"
:disabled="disabled"
:size="size"
:class="{ 'layui-unselect': true }"
@remove="handleRemove"
@clear="handleClear"
>
<template #suffix>
<lay-icon
type="layui-icon-triangle-d"
:class="{ triangle: openState }"
></lay-icon>
</template>
</lay-tag-input>
<lay-input
v-else
:modelValue="singleValue"
:placeholder="placeholder"
:allow-clear="allowClear"
:readonly="!showSearch"
:disabled="disabled"
:class="{ 'layui-unselect': !showSearch }"
:size="size"
@compositionstart="onCompositionstart"
@compositionend="onCompositionend"
@Input="handleSearch"
@clear="handleClear"
>
<template #suffix>
<lay-icon
type="layui-icon-triangle-d"
:class="{ triangle: openState }"
></lay-icon>
</template>
</lay-input>
<template #content>
<dl class="layui-select-content">
<div class="layui-select-search" v-if="multiple && showSearch">
<lay-input
:modelValue="searchValue"
:placeholder="searchPlaceholder"
@Input="handleSearch"
@compositionstart="onCompositionstart"
@compositionend="onCompositionend"
prefix-icon="layui-icon-search"
size="sm"
></lay-input>
</div>
<template v-if="items">
<lay-select-option
v-for="(item, index) in items"
v-bind="item"
:key="index"
></lay-select-option>
</template>
<slot></slot>
</dl>
</template>
</lay-dropdown>
</div>
</template>