Merge branch 'feat-tag-input' into next
This commit is contained in:
commit
50e8e2a419
@ -36,8 +36,14 @@ import {
|
|||||||
computed,
|
computed,
|
||||||
toRef,
|
toRef,
|
||||||
StyleValue,
|
StyleValue,
|
||||||
|
Ref,
|
||||||
} from "vue";
|
} from "vue";
|
||||||
import { onClickOutside, useEventListener, useThrottleFn } from "@vueuse/core";
|
import {
|
||||||
|
onClickOutside,
|
||||||
|
useEventListener,
|
||||||
|
useResizeObserver,
|
||||||
|
useThrottleFn,
|
||||||
|
} from "@vueuse/core";
|
||||||
|
|
||||||
export type PopperTrigger = "click" | "hover" | "focus" | "contextMenu";
|
export type PopperTrigger = "click" | "hover" | "focus" | "contextMenu";
|
||||||
|
|
||||||
@ -209,18 +215,35 @@ onClickOutside(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
useResizeObserver(triggerRefEl, () => {
|
||||||
|
updatePosistion();
|
||||||
|
});
|
||||||
|
|
||||||
|
let popperObserver: { stop: any; isSupported?: Ref<boolean> } | undefined =
|
||||||
|
undefined;
|
||||||
|
|
||||||
|
watch(innerVisible, (isShow) => {
|
||||||
|
updatePosistion();
|
||||||
|
if (isShow) {
|
||||||
|
popperObserver = useResizeObserver(popperRefEl, () => {
|
||||||
|
updatePosistion();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
popperObserver && popperObserver.stop();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.visible,
|
() => props.visible,
|
||||||
(isShow) => (isShow ? doShow() : doHidden())
|
(isShow) => (isShow ? doShow() : doHidden())
|
||||||
);
|
);
|
||||||
|
|
||||||
watch(innerVisible, (val) => {
|
watch(
|
||||||
updatePosistion();
|
() => props.content,
|
||||||
});
|
() => {
|
||||||
|
updatePosistion();
|
||||||
watch([() => props.content, () => slots.content && slots?.content()], (val) => {
|
}
|
||||||
innerVisible.value && updatePosistion();
|
);
|
||||||
});
|
|
||||||
|
|
||||||
const isScrollElement = function (element: HTMLElement) {
|
const isScrollElement = function (element: HTMLElement) {
|
||||||
return (
|
return (
|
||||||
|
@ -1,64 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
export default {
|
|
||||||
name: "Tag",
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { ref } from "vue";
|
|
||||||
|
|
||||||
export interface LayTagProps {
|
|
||||||
theme?: string;
|
|
||||||
closable?: boolean;
|
|
||||||
size?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = withDefaults(defineProps<LayTagProps>(), {
|
|
||||||
closable: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
const emit = defineEmits(["close"]);
|
|
||||||
|
|
||||||
const visible = ref(true);
|
|
||||||
|
|
||||||
const handleClose = (e: MouseEvent) => {
|
|
||||||
visible.value = false;
|
|
||||||
emit("close", e);
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
<template>
|
|
||||||
<lay-badge v-if="visible" theme="green">
|
|
||||||
<template v-if="$slots.default" #default>
|
|
||||||
<slot name="default"></slot>
|
|
||||||
<lay-icon
|
|
||||||
v-if="closable"
|
|
||||||
type="layui-icon-close"
|
|
||||||
@click.stop="handleClose"
|
|
||||||
></lay-icon>
|
|
||||||
</template>
|
|
||||||
</lay-badge>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!-- <template v-for="(item, index) in selectItem.label" :key="index">
|
|
||||||
<lay-badge theme="green">
|
|
||||||
<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> -->
|
|
@ -1,65 +1,138 @@
|
|||||||
.layui-input-tag {
|
@import "../tag/index.less";
|
||||||
position: relative;
|
@import "../popper/index.less";
|
||||||
display: block;
|
@import "../tooltip/index.less";
|
||||||
|
|
||||||
|
@tag-input-lg: 44px;
|
||||||
|
@tag-input-md: 38px;
|
||||||
|
@tag-input-sm: 32px;
|
||||||
|
@tag-input-xs: 26px;
|
||||||
|
@tag-input-boeder: 1px;
|
||||||
|
@tag-input-inner-padding-lg: 2px;
|
||||||
|
@tag-input-inner-padding-md: 2px;
|
||||||
|
@tag-input-inner-padding-sm: 1px;
|
||||||
|
@tag-input-inner-padding-xs: 1px;
|
||||||
|
@tag-margin-top-lg: 2px;
|
||||||
|
@tag-margin-top-md: 2px;
|
||||||
|
@tag-margin-top-sm: 1px;
|
||||||
|
@tag-margin-top-xs: 1px;
|
||||||
|
@tag-margin-bottom-lg: 2px;
|
||||||
|
@tag-margin-bottom-md: 2px;
|
||||||
|
@tag-margin-bottom-sm: 1px;
|
||||||
|
@tag-margin-bottom-xs: 1px;
|
||||||
|
|
||||||
|
.layui-tag-input {
|
||||||
|
display: inline-flex;
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: auto;
|
||||||
|
border-width: @tag-input-boeder;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: var(--input-border-color);
|
||||||
|
border-radius: var(--input-border-radius);
|
||||||
padding: 0 5px;
|
padding: 0 5px;
|
||||||
height: auto;
|
cursor: text;
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
.layui-input-prefix {
|
&-inner {
|
||||||
display: inline;
|
|
||||||
text-align: left;
|
|
||||||
height: 100%;
|
|
||||||
flex: unset;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layui-input-suffix{
|
|
||||||
position: absolute;
|
|
||||||
right: 3px;
|
|
||||||
bottom: 0;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layui-input {
|
|
||||||
display: inline-block;
|
|
||||||
padding-left: 0;
|
|
||||||
width: auto;
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
max-width: 100%;
|
overflow: hidden;
|
||||||
min-width: 12px;
|
line-height: 0;
|
||||||
|
padding: @tag-input-inner-padding-md 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.layui-input-tag-collapsed-panel,
|
&-mirror {
|
||||||
.layui-input-tag {
|
position: absolute;
|
||||||
.layui-badge {
|
top: 0;
|
||||||
margin-right: 5px;
|
left: 0;
|
||||||
height: 28px;
|
white-space: pre;
|
||||||
line-height: 28px;
|
visibility: hidden;
|
||||||
user-select: none;
|
pointer-events: none;
|
||||||
white-space: pre-wrap;
|
}
|
||||||
|
|
||||||
.layui-icon {
|
&-clear {
|
||||||
font-size: 12px;
|
display: none;
|
||||||
padding-left: 3px;
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
&:hover {
|
&-clear:hover {
|
||||||
cursor: pointer;
|
opacity: 0.5;
|
||||||
color: #ff5722;
|
}
|
||||||
}
|
|
||||||
|
& &-inner-input {
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.4;
|
||||||
|
|
||||||
|
.layui-tag-input-clear {
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.layui-tag {
|
||||||
|
margin-right: 5px;
|
||||||
|
margin-top: 2px;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-collapsed-panel {
|
||||||
|
white-space: normal;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
width: fit-content;
|
||||||
|
max-width: 240px;
|
||||||
|
height: auto;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.layui-tag {
|
||||||
|
margin-right: 5px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.set-size(@size) {
|
||||||
|
@height: ~'tag-input-@{size}';
|
||||||
|
@tag-margin-top: ~'tag-margin-top-@{size}';
|
||||||
|
@tag-margin-bottom: ~'tag-margin-bottom-@{size}';
|
||||||
|
@inner-padding: ~'tag-input-inner-padding-@{size}';
|
||||||
|
|
||||||
|
&.layui-tag-input-@{size} {
|
||||||
|
min-height: @@height;
|
||||||
|
|
||||||
|
.layui-tag-input-inner-input {
|
||||||
|
height: @@height - (@@inner-padding + @tag-input-boeder)* 2;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layui-tag-input-inner {
|
||||||
|
padding: @@inner-padding 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layui-tag {
|
||||||
|
margin-top: @@tag-margin-top;
|
||||||
|
margin-bottom: @@tag-margin-bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.set-size(lg);
|
||||||
|
.set-size(md);
|
||||||
|
.set-size(sm);
|
||||||
|
.set-size(xs);
|
||||||
}
|
}
|
||||||
|
|
||||||
.layui-input-tag-collapsed-panel {
|
.layui-tag-input:hover,
|
||||||
white-space: normal;
|
.layui-tag-input:focus-within {
|
||||||
display: flex;
|
border-color: #d2d2d2 !important;
|
||||||
align-items: center;
|
.layui-tag-input-clear{
|
||||||
flex-wrap: wrap;
|
display: flex;
|
||||||
width: fit-content;
|
|
||||||
max-width: 200px;
|
|
||||||
height: auto;
|
|
||||||
overflow: hidden;
|
|
||||||
.layui-badge{
|
|
||||||
margin-bottom: 4px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,9 +5,18 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import "./index.less";
|
import "./index.less";
|
||||||
import Tag from "./Tag.vue";
|
import LayTag, { LayTagProps } from "../tag/index.vue";
|
||||||
import LayToopTip from "../tooltip/index.vue";
|
import LayToopTip from "../tooltip/index.vue";
|
||||||
import { onMounted, shallowRef, ref, watch, computed } from "vue";
|
import {
|
||||||
|
onMounted,
|
||||||
|
shallowRef,
|
||||||
|
ref,
|
||||||
|
watch,
|
||||||
|
computed,
|
||||||
|
reactive,
|
||||||
|
nextTick,
|
||||||
|
} from "vue";
|
||||||
|
import { reactiveOmit, useResizeObserver, useVModel } from "@vueuse/core";
|
||||||
|
|
||||||
export interface TagData {
|
export interface TagData {
|
||||||
value?: string | number;
|
value?: string | number;
|
||||||
@ -17,7 +26,7 @@ export interface TagData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface LayInputTagProps {
|
export interface LayInputTagProps {
|
||||||
modelValue?: TagData[];
|
modelValue?: (string | number | TagData)[];
|
||||||
inputValue?: string;
|
inputValue?: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
@ -26,7 +35,8 @@ export interface LayInputTagProps {
|
|||||||
max?: number;
|
max?: number;
|
||||||
minCollapsedNum?: number;
|
minCollapsedNum?: number;
|
||||||
collapseTagsTooltip?: boolean;
|
collapseTagsTooltip?: boolean;
|
||||||
size?: "md" | "sm" | "xs";
|
size?: "lg" | "md" | "sm" | "xs";
|
||||||
|
tagProps?: LayTagProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<LayInputTagProps>(), {
|
const props = withDefaults(defineProps<LayInputTagProps>(), {
|
||||||
@ -34,33 +44,60 @@ const props = withDefaults(defineProps<LayInputTagProps>(), {
|
|||||||
placeholder: "",
|
placeholder: "",
|
||||||
readonly: false,
|
readonly: false,
|
||||||
allowClear: true,
|
allowClear: true,
|
||||||
minCollapsedNum: 10,
|
minCollapsedNum: 3,
|
||||||
|
size: "md",
|
||||||
//max:3
|
//max:3
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(["update:modelValue", "update:inputValue"]);
|
const emit = defineEmits(["update:modelValue", "update:inputValue"]);
|
||||||
|
|
||||||
const mirrorRef = shallowRef<HTMLElement | undefined>(undefined);
|
const mirrorRefEl = shallowRef<HTMLElement | undefined>(undefined);
|
||||||
const inputRef = shallowRef<HTMLElement | undefined>(undefined);
|
const inputRefEl = shallowRef<HTMLInputElement | undefined>(undefined);
|
||||||
|
const oldInputValue = ref<string>("");
|
||||||
const tagData = ref<TagData[]>(props.modelValue ?? []);
|
const compositionValue = ref<string>("");
|
||||||
const inputValue = ref<string>();
|
const isComposing = ref(false);
|
||||||
const oldInputValue = ref<string>();
|
const inputStyle = reactive({ width: "15px" });
|
||||||
|
const inputValue = useVModel(props, "inputValue", emit, { defaultValue: "" });
|
||||||
|
const tagData = useVModel(props, "modelValue", emit, {
|
||||||
|
deep: true,
|
||||||
|
defaultValue: [] as TagData[],
|
||||||
|
});
|
||||||
|
const tagProps = reactiveOmit(props.tagProps ?? {}, 'closable','size', 'disabled')
|
||||||
|
|
||||||
const computedTagData = computed(() => {
|
const computedTagData = computed(() => {
|
||||||
|
if (!tagData.value) return;
|
||||||
return props.minCollapsedNum
|
return props.minCollapsedNum
|
||||||
? tagData.value?.slice(0, props.minCollapsedNum)
|
? tagData.value?.slice(0, props.minCollapsedNum)
|
||||||
: tagData.value;
|
: tagData.value;
|
||||||
});
|
});
|
||||||
|
|
||||||
const collapsedTagData = computed(() => {
|
const collapsedTagData = computed(() => {
|
||||||
|
if (!tagData.value) return;
|
||||||
return props.minCollapsedNum && tagData.value?.length > props.minCollapsedNum
|
return props.minCollapsedNum && tagData.value?.length > props.minCollapsedNum
|
||||||
? tagData.value?.slice(props.minCollapsedNum)
|
? tagData.value?.slice(props.minCollapsedNum)
|
||||||
: [];
|
: [];
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleInputEnter = (e: KeyboardEvent) => {
|
const handleInput = function (event: Event) {
|
||||||
e.preventDefault();
|
if (isComposing.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
inputValue.value = (event.target as HTMLInputElement).value;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleComposition = (event: CompositionEvent) => {
|
||||||
|
if (event.type === "compositionend") {
|
||||||
|
isComposing.value = false;
|
||||||
|
compositionValue.value = "";
|
||||||
|
handleInput(event);
|
||||||
|
} else {
|
||||||
|
isComposing.value = true;
|
||||||
|
compositionValue.value = inputValue.value + (event.data ?? "");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEnter = (event: KeyboardEvent) => {
|
||||||
|
event.preventDefault();
|
||||||
const valueStr = inputValue.value ? String(inputValue.value).trim() : "";
|
const valueStr = inputValue.value ? String(inputValue.value).trim() : "";
|
||||||
if (!valueStr || !tagData.value) return;
|
if (!valueStr || !tagData.value) return;
|
||||||
const isLimit = props.max && tagData.value?.length >= props.max;
|
const isLimit = props.max && tagData.value?.length >= props.max;
|
||||||
@ -73,86 +110,137 @@ const handleInputEnter = (e: KeyboardEvent) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlerInputBackspaceKeyUp = (e: KeyboardEvent) => {
|
const handleBackspaceKeyUp = (event: KeyboardEvent) => {
|
||||||
if (!tagData.value || !tagData.value.length) return;
|
if (!tagData.value || !tagData.value.length) return;
|
||||||
if (!oldInputValue.value && ["Backspace", "Delete"].includes(e.code)) {
|
if (!oldInputValue.value && ["Backspace", "Delete"].includes(event.code)) {
|
||||||
tagData.value = tagData.value.slice(0, -1);
|
tagData.value = tagData.value.slice(0, -1);
|
||||||
}
|
}
|
||||||
oldInputValue.value = inputValue.value;
|
oldInputValue.value = inputValue.value ?? "";
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlerClearClick = (e: MouseEvent) => {
|
const handleFocus = () => {
|
||||||
|
(inputRefEl.value as HTMLInputElement)?.focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBlur = () => {
|
||||||
|
(inputRefEl.value as HTMLInputElement)?.blur();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClearClick = (e: MouseEvent) => {
|
||||||
|
if (props.disabled || props.readonly || !props.allowClear) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
tagData.value = [];
|
tagData.value = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlerClose = (index: number) => {
|
const handleClose = (index: number) => {
|
||||||
if (!tagData.value) return;
|
if (!tagData.value) return;
|
||||||
const arr = [...tagData.value];
|
const arr = [...tagData.value];
|
||||||
arr.splice(index, 1);
|
arr.splice(index, 1);
|
||||||
tagData.value = arr;
|
tagData.value = arr;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlerFocus = (e: MouseEvent) => {
|
const setInputWidth = (width: number) => {
|
||||||
(
|
if (width > 15) {
|
||||||
(e.target as HTMLElement).querySelector(".layui-input") as HTMLInputElement
|
inputStyle.width = `${width}px`;
|
||||||
)?.focus();
|
} else {
|
||||||
|
inputStyle.width = "15px";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
watch(tagData, (val) => {
|
const handleResize = () => {
|
||||||
emit("update:modelValue", val);
|
if (mirrorRefEl.value) {
|
||||||
|
setInputWidth(mirrorRefEl.value.offsetWidth);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const cls = computed(() => [
|
||||||
|
`layui-tag-input`,
|
||||||
|
`layui-tag-input-${props.size}`,
|
||||||
|
{
|
||||||
|
"layui-tag-input-disabled": props.disabled,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
useResizeObserver(mirrorRefEl, () => {
|
||||||
|
handleResize();
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(inputValue, (val) => {
|
watch(
|
||||||
emit("update:inputValue", val);
|
() => inputValue.value,
|
||||||
|
(val) => {
|
||||||
|
if (inputRefEl.value && !isComposing.value) {
|
||||||
|
nextTick(() => {
|
||||||
|
inputRefEl.value!.value = val ?? "";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
handleResize();
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {});
|
defineExpose({
|
||||||
|
focus: handleFocus,
|
||||||
|
blur: handleBlur,
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<lay-input
|
<div :class="cls" @click="handleFocus">
|
||||||
class="layui-input-tag"
|
<span ref="mirrorRefEl" class="layui-tag-input-mirror">
|
||||||
v-model="inputValue"
|
{{ compositionValue || inputValue || placeholder }}
|
||||||
:placeholder="placeholder"
|
</span>
|
||||||
:readonly="readonly"
|
<span v-if="$slots.prefix">
|
||||||
@keydown.enter="handleInputEnter"
|
<slot name="prefix"></slot>
|
||||||
@keyup="handlerInputBackspaceKeyUp"
|
</span>
|
||||||
@click="handlerFocus"
|
<span class="layui-tag-input-inner">
|
||||||
>
|
|
||||||
<template #prefix>
|
|
||||||
<template
|
<template
|
||||||
v-for="(item, index) of computedTagData"
|
v-for="(item, index) of computedTagData"
|
||||||
:key="`${item}-${index}`"
|
:key="`${item}-${index}`"
|
||||||
>
|
>
|
||||||
<Tag :closable="!readonly" @close="handlerClose(index)">
|
<LayTag v-bind="tagProps" :closable="!readonly && !disabled" :size="size" @close="handleClose(index)">
|
||||||
{{ item }}
|
{{ item }}
|
||||||
</Tag>
|
</LayTag>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="computedTagData?.length != tagData?.length">
|
<template v-if="computedTagData?.length != tagData?.length">
|
||||||
<LayToopTip :isDark="false">
|
<LayToopTip :isDark="false" trigger="click" popperStyle="padding:6px">
|
||||||
<Tag key="more" :closable="false"
|
<LayTag v-bind="tagProps" key="more" :closable="false" :size="size">
|
||||||
>+{{ tagData?.length - computedTagData?.length }}...</Tag
|
+{{tagData!.length - computedTagData!.length }}...
|
||||||
>
|
</LayTag>
|
||||||
<template #content>
|
<template #content>
|
||||||
<div class="layui-input-tag-collapsed-panel">
|
<div class="layui-tag-input-collapsed-panel">
|
||||||
<template
|
<LayTag
|
||||||
v-for="(item, index) of tagData"
|
v-for="(item, index) of collapsedTagData"
|
||||||
:key="`${item}-${index}`"
|
:key="`${item}-${index}`"
|
||||||
|
v-bind="tagProps"
|
||||||
|
:closable="!readonly && !disabled"
|
||||||
|
:size="size"
|
||||||
|
@close="handleClose(index + (minCollapsedNum ?? 0))"
|
||||||
>
|
>
|
||||||
<Tag
|
{{ item }}
|
||||||
v-if="index >= minCollapsedNum"
|
</LayTag>
|
||||||
:closable="!readonly"
|
|
||||||
@close="handlerClose(index)"
|
|
||||||
>
|
|
||||||
{{ item }}
|
|
||||||
</Tag>
|
|
||||||
</template>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</LayToopTip>
|
</LayToopTip>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
<input
|
||||||
<template #suffix v-if="allowClear && tagData?.length">
|
ref="inputRefEl"
|
||||||
<lay-icon type="layui-icon-close-fill" @click.stop="handlerClearClick" />
|
class="layui-tag-input-inner-input"
|
||||||
</template>
|
:style="inputStyle"
|
||||||
</lay-input>
|
:disabled="disabled"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:readonly="readonly"
|
||||||
|
@keydown.enter="handleEnter"
|
||||||
|
@keyup="handleBackspaceKeyUp"
|
||||||
|
@input="handleInput"
|
||||||
|
@compositionstart="handleComposition"
|
||||||
|
@compositionupdate="handleComposition"
|
||||||
|
@compositionend="handleComposition"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span v-if="allowClear && tagData?.length" class="layui-tag-input-clear">
|
||||||
|
<lay-icon type="layui-icon-close-fill" @click.stop="handleClearClick" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -62,7 +62,7 @@ const props = defineProps({
|
|||||||
type: [String, Array, Object],
|
type: [String, Array, Object],
|
||||||
},
|
},
|
||||||
popperStyle: {
|
popperStyle: {
|
||||||
type: Object as PropType<StyleValue>,
|
type: [String, Object] as PropType<StyleValue>,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const vm = getCurrentInstance()!;
|
const vm = getCurrentInstance()!;
|
||||||
|
Loading…
Reference in New Issue
Block a user