♻️(component): 初步完成 select 组件重构
This commit is contained in:
parent
ff335e56df
commit
f52ff6207b
@ -42,6 +42,8 @@ const matchModule: string[] = [
|
|||||||
"empty",
|
"empty",
|
||||||
"dropdownMenu",
|
"dropdownMenu",
|
||||||
"dropdownMenuItem",
|
"dropdownMenuItem",
|
||||||
|
"tag",
|
||||||
|
"tagInput"
|
||||||
];
|
];
|
||||||
|
|
||||||
export default (): UserConfigExport => {
|
export default (): UserConfigExport => {
|
||||||
|
@ -1,173 +1,12 @@
|
|||||||
@import "../badge/index.less";
|
|
||||||
@import "../checkbox/index.less";
|
|
||||||
@import "../input/index.less";
|
|
||||||
|
|
||||||
@select-lg: 44px;
|
|
||||||
@select-md: 38px;
|
|
||||||
@select-sm: 32px;
|
|
||||||
@select-xs: 26px;
|
|
||||||
@select-lg-badge:32px;
|
|
||||||
@select-md-badge:26px;
|
|
||||||
@select-sm-badge:20px;
|
|
||||||
@select-xs-badge:14px;
|
|
||||||
@select-lg-width: 260px;
|
|
||||||
@select-md-width: 220px;
|
|
||||||
@select-sm-width: 180px;
|
|
||||||
@select-xs-width: 140px;
|
|
||||||
|
|
||||||
.set-size(@size,@badge-size,@width) {
|
|
||||||
& {
|
|
||||||
width: @width;
|
|
||||||
height: @size;
|
|
||||||
.layui-input {
|
|
||||||
height: @size;
|
|
||||||
line-height: @size;
|
|
||||||
}
|
|
||||||
.layui-badge{
|
|
||||||
height: @badge-size;
|
|
||||||
line-height: @badge-size;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dl.layui-anim-upbit > dd input[type="checkbox"] {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
dl.layui-anim-upbit > dd .layui-form-checkbox,
|
|
||||||
.layui-form-item dl.layui-anim-upbit > dd .layui-form-checkbox[lay-skin] {
|
|
||||||
margin-top: -3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layui-multiple-select-row {
|
|
||||||
position: absolute;
|
|
||||||
height: 100%;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 34px;
|
|
||||||
padding: 5px 0 5px 6px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
overflow: hidden;
|
|
||||||
overflow-x: scroll;
|
|
||||||
cursor: pointer;
|
|
||||||
.layui-multiple-select-badge {
|
|
||||||
width: ms-max-content;
|
|
||||||
width: max-content;
|
|
||||||
.layui-badge {
|
|
||||||
margin-left: 5px;
|
|
||||||
height: 25px;
|
|
||||||
line-height: 25px;
|
|
||||||
border:1px solid #f0f0f0;
|
|
||||||
&:first-of-type {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.layui-icon {
|
|
||||||
font-size: 12px;
|
|
||||||
padding-left: 3px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&::-webkit-scrollbar {
|
|
||||||
width: 4px;
|
|
||||||
height: 4px;
|
|
||||||
}
|
|
||||||
&::-webkit-scrollbar-thumb {
|
|
||||||
height: 50px;
|
|
||||||
background-color: whitesmoke;
|
|
||||||
border-radius: 6px;
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
&::-webkit-scrollbar-thumb:hover {
|
|
||||||
height: 50px;
|
|
||||||
background-color: whitesmoke;
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.layui-select {
|
.layui-select {
|
||||||
height: 38px;
|
width: 220px;
|
||||||
line-height: 1.3;
|
|
||||||
line-height: 38px\9;
|
|
||||||
border-width: 1px;
|
|
||||||
border-style: solid;
|
|
||||||
background-color: #fff;
|
|
||||||
border-color: #eee;
|
|
||||||
color: rgba(0, 0, 0, 0.85);
|
|
||||||
border-radius: 2px;
|
|
||||||
padding: 0 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.layui-select::-webkit-input-placeholder {
|
.layui-select-options {
|
||||||
line-height: 1.3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layui-form-select {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layui-select-title{
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layui-select-title .layui-input {
|
|
||||||
padding-right: 36px;
|
|
||||||
padding-left: 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layui-form-select .layui-edge {
|
|
||||||
position: absolute;
|
|
||||||
right: 10px;
|
|
||||||
top: 50%;
|
|
||||||
margin-top: -3px;
|
|
||||||
cursor: pointer;
|
|
||||||
border-width: 6px;
|
|
||||||
border-top-color: var(--global-neutral-color-8);
|
|
||||||
border-top-style: solid;
|
|
||||||
transition: all 0.3s;
|
|
||||||
-webkit-transition: all 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layui-input-icon-area{
|
|
||||||
position: absolute;
|
|
||||||
right: 10px;
|
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
z-index: 1;
|
|
||||||
cursor: pointer;
|
|
||||||
.layui-icon-close-fill{
|
|
||||||
margin-left: 10px;
|
|
||||||
color: rgba(0, 0, 0, 0.45);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.layui-form-select .layui-icon-triangle-d {
|
|
||||||
display: inline-block;
|
|
||||||
transition: all 0.3s;
|
|
||||||
-webkit-transition: all 0.3s;
|
|
||||||
color:var(--global-neutral-color-8);
|
|
||||||
}
|
|
||||||
|
|
||||||
.layui-form-select dl {
|
|
||||||
display: none;
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 42px;
|
|
||||||
padding: 5px 0;
|
padding: 5px 0;
|
||||||
z-index: 899;
|
|
||||||
min-width: 100%;
|
|
||||||
border: 1px solid var(--global-neutral-color-3);
|
|
||||||
max-height: 300px;
|
|
||||||
overflow-y: auto;
|
|
||||||
background-color: #fff;
|
|
||||||
border-radius: var(--global-border-radius);
|
|
||||||
box-sizing: border-box;
|
|
||||||
box-shadow: 1px 1px 4px rgb(0 0 0 / 8%);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.layui-form-select dl dd,
|
.layui-select-options .layui-select-option {
|
||||||
.layui-form-select dl dt {
|
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
line-height: 36px;
|
line-height: 36px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
@ -175,66 +14,7 @@ dl.layui-anim-upbit > dd .layui-form-checkbox,
|
|||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
.layui-form-select dl dt {
|
.layui-select-options .layui-select-option.layui-this {
|
||||||
font-size: 12px;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layui-form-select dl dd {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layui-form-select dl dd:hover {
|
|
||||||
background-color: var(--global-neutral-color-2);
|
|
||||||
-webkit-transition: 0.5s all;
|
|
||||||
transition: 0.5s all;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layui-form-select .layui-select-group dd {
|
|
||||||
padding-left: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layui-form-select dl dd.layui-select-tips {
|
|
||||||
padding-left: 10px !important;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layui-form-select dl dd.layui-this {
|
|
||||||
background-color: var(--global-neutral-color-2);
|
background-color: var(--global-neutral-color-2);
|
||||||
color: var(--global-checked-color);
|
color: var(--global-checked-color);
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layui-form-checkbox,
|
|
||||||
.layui-form-select dl dd.layui-disabled {
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layui-form-selected dl {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layui-multiple-select-input {
|
|
||||||
margin-bottom: 5px;
|
|
||||||
padding: 0 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
.layui-input {
|
|
||||||
height: 30px !important;
|
|
||||||
line-height: 30px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.layui-form-select{
|
|
||||||
&[size="lg"] {
|
|
||||||
.set-size(@select-lg, @select-lg-badge, @select-lg-width);
|
|
||||||
}
|
|
||||||
&[size="md"] {
|
|
||||||
.set-size(@select-md, @select-md-badge, @select-md-width);
|
|
||||||
}
|
|
||||||
&[size="sm"] {
|
|
||||||
.set-size(@select-sm, @select-sm-badge, @select-sm-width);
|
|
||||||
}
|
|
||||||
&[size="xs"] {
|
|
||||||
.set-size(@select-xs, @select-xs-badge, @select-xs-width);
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -6,286 +6,72 @@ export default {
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import "./index.less";
|
import "./index.less";
|
||||||
import LaySelectOption from "../selectOption/index.vue";
|
import { provide, computed, WritableComputedRef } from "vue";
|
||||||
import { provide, ref, watch, computed, Ref, nextTick, shallowRef } from "vue";
|
|
||||||
import LayBadge from "../badge/index.vue";
|
|
||||||
import LayInput from "../input/index.vue";
|
import LayInput from "../input/index.vue";
|
||||||
import LayScroll from "../scroll/index.vue";
|
import LayTagInput from "../tagInput/index.vue";
|
||||||
import { onClickOutside } from "@vueuse/core";
|
import LayDropdown from "../dropdown/index.vue";
|
||||||
import { SelectItem } from "../../types";
|
import LaySelectOption, { LaySelectOptionProps } from "../selectOption/index.vue";
|
||||||
|
|
||||||
export interface LaySelectProps {
|
export interface LaySelectProps {
|
||||||
name?: string;
|
name?: string;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
showEmpty?: boolean;
|
|
||||||
emptyMessage?: string;
|
|
||||||
modelValue?: any;
|
modelValue?: any;
|
||||||
multiple?: boolean;
|
multiple?: boolean;
|
||||||
create?: boolean;
|
create?: boolean;
|
||||||
items?: {
|
items?: LaySelectOptionProps[];
|
||||||
label: string;
|
|
||||||
value: any;
|
|
||||||
key: string;
|
|
||||||
disabled: boolean;
|
|
||||||
keyword: string;
|
|
||||||
}[];
|
|
||||||
size?: "lg" | "md" | "sm" | "xs";
|
size?: "lg" | "md" | "sm" | "xs";
|
||||||
allowClear?: boolean;
|
allowClear?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectRef = shallowRef<undefined | HTMLElement>(undefined);
|
export interface SelectEmits {
|
||||||
const multipleSearchInputRef = shallowRef<HTMLElement | undefined>(undefined);
|
(e: "update:modelValue", value: string): void;
|
||||||
|
(e: "change", value: string): void;
|
||||||
onClickOutside(selectRef, (event: Event) => {
|
}
|
||||||
openState.value = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
const props = withDefaults(defineProps<LaySelectProps>(), {
|
const props = withDefaults(defineProps<LaySelectProps>(), {
|
||||||
modelValue: null,
|
modelValue: null,
|
||||||
placeholder: "请选择",
|
placeholder: "请选择",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
showEmpty: true,
|
|
||||||
multiple: false,
|
multiple: false,
|
||||||
create: false,
|
create: false,
|
||||||
size: "md",
|
size: "md",
|
||||||
allowClear: false,
|
allowClear: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const openState = ref(false);
|
const emits = defineEmits<SelectEmits>();
|
||||||
|
|
||||||
const open = function () {
|
const selectedValue = computed({
|
||||||
if (props.disabled) {
|
|
||||||
openState.value = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
openState.value = !openState.value;
|
|
||||||
nextTick(() => {
|
|
||||||
multipleSearchInputRef.value?.querySelector("input")?.focus();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const emit = defineEmits(["update:modelValue", "change", "search", "create"]);
|
|
||||||
|
|
||||||
const selectItem = ref<SelectItem>({
|
|
||||||
value: !props.multiple
|
|
||||||
? props.modelValue
|
|
||||||
: props.modelValue
|
|
||||||
? ([] as any[]).concat(props.modelValue)
|
|
||||||
: [],
|
|
||||||
label: props.multiple ? [] : null,
|
|
||||||
multiple: props.multiple,
|
|
||||||
} as SelectItem);
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => selectItem.value.value,
|
|
||||||
(val) => {
|
|
||||||
emit("update:modelValue", val);
|
|
||||||
emit("change", val);
|
|
||||||
},
|
|
||||||
{ deep: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
watch(props, () => {
|
|
||||||
let value = props.modelValue;
|
|
||||||
if (props.multiple) {
|
|
||||||
if (Array.isArray(value)) {
|
|
||||||
selectItem.value.value = value;
|
|
||||||
selectItem.value.label = value.map((o) => ItemsMap.value[o]);
|
|
||||||
} else {
|
|
||||||
console.error("多选时请传入数组值");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
selectItem.value.value = value;
|
|
||||||
selectItem.value.label = ItemsMap.value[value] || "";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const txt = ref("");
|
|
||||||
const disabledItemMap: { [key: string | number]: boolean } = {};
|
|
||||||
const input = ref(false);
|
|
||||||
const value = computed({
|
|
||||||
set(v: any) {
|
|
||||||
txt.value = v;
|
|
||||||
emit("search", v);
|
|
||||||
},
|
|
||||||
get() {
|
get() {
|
||||||
if (input.value) {
|
return props.modelValue;
|
||||||
return txt.value;
|
|
||||||
}
|
|
||||||
return !selectItem.value.multiple && selectItem.value.value !== null
|
|
||||||
? selectItem.value.label
|
|
||||||
: null;
|
|
||||||
},
|
},
|
||||||
});
|
set(val) {
|
||||||
|
emits('update:modelValue', val);
|
||||||
const selectItemHandle = async function (
|
emits('change', val);
|
||||||
_selectItem: SelectItem,
|
|
||||||
isChecked?: boolean
|
|
||||||
) {
|
|
||||||
if (!props.multiple) {
|
|
||||||
openState.value = false;
|
|
||||||
}
|
}
|
||||||
txt.value = "";
|
})
|
||||||
disabledItemMap[_selectItem.value as string | number] =
|
|
||||||
_selectItem.disabled as boolean;
|
|
||||||
if (typeof isChecked !== "boolean") {
|
|
||||||
props.multiple
|
|
||||||
? (selectItem.value.label as any[]).push(_selectItem.label)
|
|
||||||
: (selectItem.value.label = _selectItem.label);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let values = selectItem.value.value;
|
|
||||||
if (props.multiple && Array.isArray(values)) {
|
|
||||||
const _values = values as any[];
|
|
||||||
const _labels = selectItem.value.label as any[];
|
|
||||||
if (isChecked) {
|
|
||||||
_values.push(_selectItem.value);
|
|
||||||
_labels.push(_selectItem.label);
|
|
||||||
} else {
|
|
||||||
_values.splice(_values.indexOf(_selectItem.value), 1);
|
|
||||||
_labels.splice(_labels.indexOf(_selectItem.label), 1);
|
|
||||||
}
|
|
||||||
selectItem.value.value = _values;
|
|
||||||
selectItem.value.label = _labels;
|
|
||||||
} else {
|
|
||||||
selectItem.value.value = _selectItem.value;
|
|
||||||
selectItem.value.label = _selectItem.label;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const removeItemHandle = function (e: MouseEvent, _selectItem: SelectItem) {
|
const multiple = computed(() => {
|
||||||
e.stopPropagation();
|
return props.multiple;
|
||||||
selectItemHandle(_selectItem, false);
|
})
|
||||||
};
|
|
||||||
const ItemsMap: Ref<{ [index: string]: string }> = ref({});
|
|
||||||
const selectItemPush = function (p: SelectItem) {
|
|
||||||
if (p.value !== null) {
|
|
||||||
//@ts-ignore
|
|
||||||
ItemsMap.value[p.value] = p.label;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const clear = () => {
|
provide('selectedValue', selectedValue);
|
||||||
emit("update:modelValue", props.multiple ? [] : "");
|
provide('multiple', multiple);
|
||||||
};
|
|
||||||
|
|
||||||
provide("selectItemHandle", selectItemHandle);
|
|
||||||
provide("selectItemPush", selectItemPush);
|
|
||||||
provide("selectItem", selectItem);
|
|
||||||
provide("keyword", txt);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div class="layui-select">
|
||||||
ref="selectRef"
|
<lay-dropdown update-at-scroll>
|
||||||
class="layui-unselect layui-form-select"
|
<lay-tag-input v-if="multiple" v-model="selectedValue"></lay-tag-input>
|
||||||
:class="{
|
<lay-input v-else :placeholder="placeholder" v-model="selectedValue"></lay-input>
|
||||||
'layui-form-selected': openState,
|
<template #content>
|
||||||
'layui-form-select-multiple': multiple,
|
<dl class="layui-select-options">
|
||||||
}"
|
<template v-if="items">
|
||||||
:size="size"
|
<lay-select-option v-for="(item, index) in items" v-bind="item" :key="index"></lay-select-option>
|
||||||
>
|
</template>
|
||||||
<div class="layui-select-title" @click="open">
|
<slot></slot>
|
||||||
<input
|
</dl>
|
||||||
type="text"
|
</template>
|
||||||
:placeholder="
|
</lay-dropdown>
|
||||||
selectItem.value !== null &&
|
</div>
|
||||||
Array.isArray(selectItem.value) &&
|
|
||||||
selectItem.value.length > 0
|
|
||||||
? ''
|
|
||||||
: emptyMessage ?? placeholder
|
|
||||||
"
|
|
||||||
:disabled="disabled"
|
|
||||||
v-model="value"
|
|
||||||
@input="input = true"
|
|
||||||
@blur="input = false"
|
|
||||||
:name="name"
|
|
||||||
:class="[
|
|
||||||
'layui-input',
|
|
||||||
'layui-unselect',
|
|
||||||
{ 'layui-disabled': disabled },
|
|
||||||
]"
|
|
||||||
/>
|
|
||||||
<span class="layui-input-icon-area">
|
|
||||||
<i
|
|
||||||
:class="[
|
|
||||||
'layui-icon layui-icon-triangle-d',
|
|
||||||
{ 'layui-disabled': disabled },
|
|
||||||
]"
|
|
||||||
:style="{ transform: `rotate(${openState ? 180 : 0}deg)` }"
|
|
||||||
></i>
|
|
||||||
<i
|
|
||||||
class="layui-icon layui-icon-close-fill"
|
|
||||||
v-if="(value || selectItem.label?.length) && allowClear"
|
|
||||||
@click.stop="clear"
|
|
||||||
></i>
|
|
||||||
</span>
|
|
||||||
<!-- 多选 -->
|
|
||||||
<div
|
|
||||||
v-if="selectItem.multiple && Array.isArray(selectItem.label)"
|
|
||||||
class="layui-multiple-select-row"
|
|
||||||
>
|
|
||||||
<div class="layui-multiple-select-badge">
|
|
||||||
<template v-for="(item, index) in selectItem.label" :key="index">
|
|
||||||
<lay-badge theme="gray">
|
|
||||||
<span>{{ item }}</span>
|
|
||||||
<i
|
|
||||||
:class="['layui-icon', { 'layui-icon-close': true }]"
|
|
||||||
v-if="
|
|
||||||
!disabled &&
|
|
||||||
!(
|
|
||||||
Array.isArray(selectItem.value) &&
|
|
||||||
selectItem.value.length > 0 &&
|
|
||||||
disabledItemMap[selectItem.value[index]]
|
|
||||||
)
|
|
||||||
"
|
|
||||||
@click="
|
|
||||||
removeItemHandle($event, {
|
|
||||||
label: item,
|
|
||||||
value: Array.isArray(selectItem.value)
|
|
||||||
? selectItem.value[index]
|
|
||||||
: null,
|
|
||||||
})
|
|
||||||
"
|
|
||||||
></i>
|
|
||||||
</lay-badge>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 下拉内容 -->
|
|
||||||
<dl class="layui-anim layui-anim-upbit">
|
|
||||||
<div ref="multipleSearchInputRef" class="layui-multiple-select-input">
|
|
||||||
<lay-input
|
|
||||||
v-if="multiple"
|
|
||||||
v-model="value"
|
|
||||||
@input="input = true"
|
|
||||||
@blur="input = false"
|
|
||||||
:placeholder="placeholder"
|
|
||||||
prefix-icon="layui-icon-search"
|
|
||||||
allow-clear
|
|
||||||
>
|
|
||||||
</lay-input>
|
|
||||||
</div>
|
|
||||||
<template v-if="!multiple && showEmpty && !props.create">
|
|
||||||
<lay-select-option value="-1" :label="emptyMessage ?? placeholder" />
|
|
||||||
</template>
|
|
||||||
<template v-if="props.create">
|
|
||||||
<dd @click="emit('create', txt)">{{ txt }}</dd>
|
|
||||||
</template>
|
|
||||||
<template v-if="props.items">
|
|
||||||
<lay-select-option
|
|
||||||
v-for="(v, k) in props.items"
|
|
||||||
:key="k"
|
|
||||||
:value="v.value"
|
|
||||||
:label="v.label"
|
|
||||||
:disabled="v.disabled"
|
|
||||||
:keyword="v.keyword"
|
|
||||||
></lay-select-option>
|
|
||||||
</template>
|
|
||||||
<slot></slot>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
@ -6,11 +6,10 @@ export default {
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import LayCheckbox from "../checkbox/index.vue";
|
import LayCheckbox from "../checkbox/index.vue";
|
||||||
import { SelectItem, SelectItemHandle, SelectItemPush } from "../../types";
|
import { computed, ComputedRef, inject, WritableComputedRef } from "vue";
|
||||||
import { computed, inject, onMounted, Ref, ref } from "vue";
|
|
||||||
|
|
||||||
export interface LaySelectOptionProps {
|
export interface LaySelectOptionProps {
|
||||||
value: string | null | undefined | number;
|
value: string | object;
|
||||||
label: string;
|
label: string;
|
||||||
keyword?: string;
|
keyword?: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
@ -22,67 +21,33 @@ const props = withDefaults(defineProps<LaySelectOptionProps>(), {
|
|||||||
label: "",
|
label: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
const selectItemHandle = inject("selectItemHandle") as SelectItemHandle;
|
const selectedValue: WritableComputedRef<any> = inject("selectedValue") as WritableComputedRef<any>;
|
||||||
const selectItem = inject("selectItem") as Ref<SelectItem>;
|
const multiple: ComputedRef = inject("multiple") as ComputedRef;
|
||||||
const selectItemPush = inject("selectItemPush") as Ref<SelectItemPush>;
|
|
||||||
const keyword = inject("keyword") as Ref<string>;
|
|
||||||
|
|
||||||
const selectHandle = function () {
|
const handleSelect = () => {
|
||||||
!props.disabled && callSelectItemHandle(!selected.value);
|
if(!multiple.value) {
|
||||||
};
|
selectedValue.value = props.value;
|
||||||
const callSelectItemHandle = function (isChecked?: boolean) {
|
}
|
||||||
// console.log("callSelectItemHandle");
|
}
|
||||||
selectItemHandle(
|
|
||||||
{
|
const isSelected = computed(() => {
|
||||||
value: props.value,
|
if (multiple.value) {
|
||||||
label: props.label,
|
return selectedValue.value.indexOf(props.value) != -1;
|
||||||
disabled: props.disabled,
|
} else {
|
||||||
},
|
return selectedValue.value === props.value;
|
||||||
isChecked
|
}
|
||||||
);
|
|
||||||
};
|
|
||||||
const selected = computed({
|
|
||||||
get() {
|
|
||||||
const selectValues = selectItem.value.value;
|
|
||||||
if (Array.isArray(selectValues)) {
|
|
||||||
return (selectValues as any[]).indexOf(props.value) > -1;
|
|
||||||
}
|
|
||||||
return selectItem.value.value === props.value;
|
|
||||||
},
|
|
||||||
set(val) {},
|
|
||||||
});
|
|
||||||
const callSelectItemPush = function () {
|
|
||||||
let item = {
|
|
||||||
value: props.value,
|
|
||||||
label: props.label,
|
|
||||||
disabled: props.disabled,
|
|
||||||
};
|
|
||||||
// @ts-ignore
|
|
||||||
selectItemPush(item);
|
|
||||||
};
|
|
||||||
const search = ref("");
|
|
||||||
onMounted(() => {
|
|
||||||
search.value = props.keyword || props.label;
|
|
||||||
callSelectItemPush();
|
|
||||||
selected.value && callSelectItemHandle();
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<dd
|
<dd class="layui-select-option" :class="{ 'layui-this': isSelected && !multiple }" @click="handleSelect">
|
||||||
v-show="keyword ? search.includes(keyword) : true"
|
<template v-if="multiple">
|
||||||
:value="value"
|
<lay-checkbox v-model="selectedValue" :value="value" skin="primary"
|
||||||
:class="[{ 'layui-this': selected }, { 'layui-disabled': disabled }]"
|
><slot>{{ label }}</slot></lay-checkbox
|
||||||
@click="selectHandle"
|
>
|
||||||
>
|
</template>
|
||||||
<template v-if="selectItem.multiple">
|
<template v-else>
|
||||||
<lay-checkbox
|
<slot>{{ label }}</slot>
|
||||||
skin="primary"
|
|
||||||
v-model="selected"
|
|
||||||
@change="selectHandle"
|
|
||||||
:value="props.value"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
<slot>{{ label }}</slot>
|
|
||||||
</dd>
|
</dd>
|
||||||
</template>
|
</template>
|
||||||
|
@ -660,7 +660,7 @@ onBeforeUnmount(() => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="layui-table-box-header" v-if="slot.header">
|
<div class="layui-table-box-header" v-if="slot.header">
|
||||||
<slot name="header"></slot>
|
<slot name="header"></slot>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="layui-table-box">
|
<div class="layui-table-box">
|
||||||
|
@ -8,7 +8,7 @@ import "./index.less";
|
|||||||
import { LayIcon } from "@layui/icons-vue";
|
import { LayIcon } from "@layui/icons-vue";
|
||||||
import { computed, ref } from "vue";
|
import { computed, ref } from "vue";
|
||||||
import { TinyColor } from "@ctrl/tinycolor";
|
import { TinyColor } from "@ctrl/tinycolor";
|
||||||
import { TAG_COLORS, tagType } from "./interface";
|
import { tagType } from "./interface";
|
||||||
|
|
||||||
export interface LayTagProps {
|
export interface LayTagProps {
|
||||||
type?: tagType;
|
type?: tagType;
|
||||||
|
@ -182,6 +182,12 @@ watch(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const moreCount = computed(() => {
|
||||||
|
if(tagData.value && computedTagData.value) {
|
||||||
|
return tagData.value.length - computedTagData.value.length
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
handleResize();
|
handleResize();
|
||||||
});
|
});
|
||||||
@ -216,7 +222,7 @@ defineExpose({
|
|||||||
<template v-if="computedTagData?.length != tagData?.length">
|
<template v-if="computedTagData?.length != tagData?.length">
|
||||||
<LayToopTip :isDark="false" trigger="click" popperStyle="padding:6px">
|
<LayToopTip :isDark="false" trigger="click" popperStyle="padding:6px">
|
||||||
<LayTag v-bind="tagProps" key="more" :closable="false" :size="size">
|
<LayTag v-bind="tagProps" key="more" :closable="false" :size="size">
|
||||||
+{{tagData!.length - computedTagData!.length }}...
|
+{{ moreCount }}...
|
||||||
</LayTag>
|
</LayTag>
|
||||||
<template #content>
|
<template #content>
|
||||||
<div class="layui-tag-input-collapsed-panel">
|
<div class="layui-tag-input-collapsed-panel">
|
||||||
|
3
package/component/src/utils/arrayUtil.ts
Normal file
3
package/component/src/utils/arrayUtil.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export const check = (arr: any[], value: any) => {
|
||||||
|
return arr.indexOf(value) > -1;
|
||||||
|
}
|
@ -1,2 +1,3 @@
|
|||||||
export * from "./domUtil";
|
export * from "./DomUtil";
|
||||||
export * from "./withInstall";
|
export * from "./withInstall";
|
||||||
|
export * from "./arrayUtil";
|
@ -19,6 +19,7 @@
|
|||||||
<li>[新增] tag-input 标签输入框组件。</li>
|
<li>[新增] tag-input 标签输入框组件。</li>
|
||||||
<li>[新增] table 组件 header 插槽, 用于在工具栏与表格之间插入元素。</li>
|
<li>[新增] table 组件 header 插槽, 用于在工具栏与表格之间插入元素。</li>
|
||||||
<li>[新增] tabitem 组件 icon 属性, 用于自定义 tab-item 图标。</li>
|
<li>[新增] tabitem 组件 icon 属性, 用于自定义 tab-item 图标。</li>
|
||||||
|
<li>[修复] layout 组件只引入了 footer 时, layui-layout-vertical样式不生效。</li>
|
||||||
<li>[修复] cascader 外部清空modelValue, 内部displayValue不清空问题。</li>
|
<li>[修复] cascader 外部清空modelValue, 内部displayValue不清空问题。</li>
|
||||||
<li>[修复] tolltip 组件 content 自动定位。</li>
|
<li>[修复] tolltip 组件 content 自动定位。</li>
|
||||||
<li>[修复] breadcrumb-item 组件无法正确传递 attrs 的问题。</li>
|
<li>[修复] breadcrumb-item 组件无法正确传递 attrs 的问题。</li>
|
||||||
|
Loading…
Reference in New Issue
Block a user