(component): 完成 select 组件, 新增 tag-input 组件 disabled-input 属性

This commit is contained in:
就眠儀式 2022-09-24 09:50:53 +08:00
parent f52ff6207b
commit 06149b7e77
12 changed files with 142 additions and 54 deletions

View File

@ -43,7 +43,7 @@ const matchModule: string[] = [
"dropdownMenu", "dropdownMenu",
"dropdownMenuItem", "dropdownMenuItem",
"tag", "tag",
"tagInput" "tagInput",
]; ];
export default (): UserConfigExport => { export default (): UserConfigExport => {

View File

@ -70,7 +70,6 @@ export interface LayDropdownProps {
alignPoint?: boolean; alignPoint?: boolean;
contentClass?: string | Array<string | object> | object; contentClass?: string | Array<string | object> | object;
contentStyle?: StyleValue; contentStyle?: StyleValue;
// wip
popupContainer?: string | undefined; popupContainer?: string | undefined;
} }

View File

@ -26,7 +26,10 @@ const isVertical = computed(() => {
return vNodes.some((vNode) => { return vNodes.some((vNode) => {
const componentName = (vNode.type as Component).name; const componentName = (vNode.type as Component).name;
if (!componentName) return false; if (!componentName) return false;
return [Header.name].includes(componentName) || [Footer.name].includes(componentName); return (
[Header.name].includes(componentName) ||
[Footer.name].includes(componentName)
);
}); });
}); });

View File

@ -14,7 +14,16 @@
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.layui-select-options .layui-select-option .layui-form-checkbox[lay-skin="primary"] {
padding-left: 12px;
}
.layui-select-options .layui-select-option.layui-this { .layui-select-options .layui-select-option.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-size: 700;
}
.layui-select-search {
padding: 5px 10px;
} }

View File

@ -6,11 +6,13 @@ export default {
<script setup lang="ts"> <script setup lang="ts">
import "./index.less"; import "./index.less";
import { provide, computed, WritableComputedRef } from "vue"; import { provide, computed, WritableComputedRef, ref } from "vue";
import LayInput from "../input/index.vue"; import LayInput from "../input/index.vue";
import LayTagInput from "../tagInput/index.vue"; import LayTagInput from "../tagInput/index.vue";
import LayDropdown from "../dropdown/index.vue"; import LayDropdown from "../dropdown/index.vue";
import LaySelectOption, { LaySelectOptionProps } from "../selectOption/index.vue"; import LaySelectOption, {
LaySelectOptionProps,
} from "../selectOption/index.vue";
export interface LaySelectProps { export interface LaySelectProps {
name?: string; name?: string;
@ -41,33 +43,47 @@ const props = withDefaults(defineProps<LaySelectProps>(), {
const emits = defineEmits<SelectEmits>(); const emits = defineEmits<SelectEmits>();
const searchValue = ref("");
const selectedValue = computed({ const selectedValue = computed({
get() { get() {
return props.modelValue; return props.modelValue;
}, },
set(val) { set(val) {
emits('update:modelValue', val); emits("update:modelValue", val);
emits('change', val); emits("change", val);
} },
}) });
const multiple = computed(() => { const multiple = computed(() => {
return props.multiple; return props.multiple;
}) });
provide('selectedValue', selectedValue); provide("selectedValue", selectedValue);
provide('multiple', multiple); provide("searchValue", searchValue);
provide("multiple", multiple);
</script> </script>
<template> <template>
<div class="layui-select"> <div class="layui-select">
<lay-dropdown update-at-scroll> <lay-dropdown update-at-scroll>
<lay-tag-input v-if="multiple" v-model="selectedValue"></lay-tag-input> <lay-tag-input v-if="multiple" v-model="selectedValue" :disabledInput="true"></lay-tag-input>
<lay-input v-else :placeholder="placeholder" v-model="selectedValue"></lay-input> <lay-input
v-else
:placeholder="placeholder"
v-model="selectedValue"
></lay-input>
<template #content> <template #content>
<dl class="layui-select-options"> <dl class="layui-select-options">
<div class="layui-select-search">
<lay-input v-model="searchValue" size="sm" placeholder="请选择" prefix-icon="layui-icon-search"></lay-input>
</div>
<template v-if="items"> <template v-if="items">
<lay-select-option v-for="(item, index) in items" v-bind="item" :key="index"></lay-select-option> <lay-select-option
v-for="(item, index) in items"
v-bind="item"
:key="index"
></lay-select-option>
</template> </template>
<slot></slot> <slot></slot>
</dl> </dl>

View File

@ -6,13 +6,13 @@ export default {
<script setup lang="ts"> <script setup lang="ts">
import LayCheckbox from "../checkbox/index.vue"; import LayCheckbox from "../checkbox/index.vue";
import { computed, ComputedRef, inject, WritableComputedRef } from "vue"; import { computed, ComputedRef, inject, WritableComputedRef, Ref } from "vue";
export interface LaySelectOptionProps { export interface LaySelectOptionProps {
value: string | object;
label: string; label: string;
keyword?: string; value: string | object;
disabled?: boolean; disabled?: boolean;
keyword?: string;
} }
const props = withDefaults(defineProps<LaySelectOptionProps>(), { const props = withDefaults(defineProps<LaySelectOptionProps>(), {
@ -22,32 +22,38 @@ const props = withDefaults(defineProps<LaySelectOptionProps>(), {
}); });
const selectedValue: WritableComputedRef<any> = inject("selectedValue") as WritableComputedRef<any>; const selectedValue: WritableComputedRef<any> = inject("selectedValue") as WritableComputedRef<any>;
const searchValue: Ref<string> = inject('searchValue') as Ref<string>;
const multiple: ComputedRef = inject("multiple") as ComputedRef; const multiple: ComputedRef = inject("multiple") as ComputedRef;
const handleSelect = () => { const handleSelect = () => {
if (!multiple.value) { if (!multiple.value) {
selectedValue.value = props.value; selectedValue.value = props.value;
} }
} };
const isSelected = computed(() => { const selected = computed(() => {
if (multiple.value) { if (multiple.value) {
return selectedValue.value.indexOf(props.value) != -1; return selectedValue.value.indexOf(props.value) != -1;
} else { } else {
// close dropdown
return selectedValue.value === props.value; return selectedValue.value === props.value;
} }
}); });
const display = computed(() => {
return props.keyword.indexOf(searchValue.value) > -1 || props.label.indexOf(searchValue.value) > -1;
})
</script> </script>
<template> <template>
<dd class="layui-select-option" :class="{ 'layui-this': isSelected && !multiple }" @click="handleSelect"> <dd
<template v-if="multiple"> v-show="display"
<lay-checkbox v-model="selectedValue" :value="value" skin="primary" :class="['layui-select-option', { 'layui-this': selected && !multiple }]"
><slot>{{ label }}</slot></lay-checkbox @click="handleSelect"
> >
<template v-if="multiple">
<lay-checkbox v-model="selectedValue" :value="value" skin="primary"></lay-checkbox>
</template> </template>
<template v-else>
<slot>{{ label }}</slot> <slot>{{ label }}</slot>
</template>
</dd> </dd>
</template> </template>

View File

@ -17,6 +17,7 @@ import {
nextTick, nextTick,
} from "vue"; } from "vue";
import { reactiveOmit, useResizeObserver, useVModel } from "@vueuse/core"; import { reactiveOmit, useResizeObserver, useVModel } from "@vueuse/core";
import { LayIcon } from "@layui/icons-vue";
export interface TagData { export interface TagData {
value?: string | number; value?: string | number;
@ -29,6 +30,7 @@ export interface LayInputTagProps {
modelValue?: (string | number | TagData)[]; modelValue?: (string | number | TagData)[];
inputValue?: string; inputValue?: string;
disabled?: boolean; disabled?: boolean;
disabledInput?: boolean;
placeholder?: string; placeholder?: string;
readonly?: boolean; readonly?: boolean;
allowClear?: boolean; allowClear?: boolean;
@ -41,12 +43,12 @@ export interface LayInputTagProps {
const props = withDefaults(defineProps<LayInputTagProps>(), { const props = withDefaults(defineProps<LayInputTagProps>(), {
disabled: false, disabled: false,
disabledInput: false,
placeholder: "", placeholder: "",
readonly: false, readonly: false,
allowClear: true, allowClear: true,
minCollapsedNum: 3, minCollapsedNum: 3,
size: "md", size: "md",
//max:3
}); });
const emit = defineEmits(["update:modelValue", "update:inputValue"]); const emit = defineEmits(["update:modelValue", "update:inputValue"]);
@ -62,6 +64,7 @@ const tagData = useVModel(props, "modelValue", emit, {
deep: true, deep: true,
defaultValue: [] as TagData[], defaultValue: [] as TagData[],
}); });
const tagProps = reactiveOmit( const tagProps = reactiveOmit(
props.tagProps ?? {}, props.tagProps ?? {},
"closable", "closable",
@ -184,9 +187,9 @@ watch(
const moreCount = computed(() => { const moreCount = computed(() => {
if (tagData.value && computedTagData.value) { if (tagData.value && computedTagData.value) {
return tagData.value.length - computedTagData.value.length return tagData.value.length - computedTagData.value.length;
} }
}) });
onMounted(() => { onMounted(() => {
handleResize(); handleResize();
@ -240,6 +243,7 @@ defineExpose({
</template> </template>
</LayToopTip> </LayToopTip>
</template> </template>
<template v-if="!disabledInput">
<input <input
ref="inputRefEl" ref="inputRefEl"
class="layui-tag-input-inner-input" class="layui-tag-input-inner-input"
@ -254,6 +258,7 @@ defineExpose({
@compositionupdate="handleComposition" @compositionupdate="handleComposition"
@compositionend="handleComposition" @compositionend="handleComposition"
/> />
</template>
</span> </span>
<span v-if="allowClear && tagData?.length" class="layui-tag-input-clear"> <span v-if="allowClear && tagData?.length" class="layui-tag-input-clear">
<lay-icon type="layui-icon-close-fill" @click.stop="handleClearClick" /> <lay-icon type="layui-icon-close-fill" @click.stop="handleClearClick" />

View File

@ -1,3 +1,3 @@
export const check = (arr: any[], value: any) => { export const check = (arr: any[], value: any) => {
return arr.indexOf(value) > -1; return arr.indexOf(value) > -1;
} };

View File

@ -24,7 +24,7 @@
</lay-dropdown-menu> </lay-dropdown-menu>
</template> </template>
</lay-dropdown> </lay-dropdown>
<lay-dropdown popupContainer=".layui-body>div"> <lay-dropdown>
<lay-button type="primary">下拉菜单</lay-button> <lay-button type="primary">下拉菜单</lay-button>
<template #content> <template #content>
<lay-dropdown-menu> <lay-dropdown-menu>

View File

@ -13,7 +13,7 @@
::: demo 使用 `lay-tag-input` 标签, 创建标签输入框。 ::: demo 使用 `lay-tag-input` 标签, 创建标签输入框。
<template> <template>
<lay-tag-input v-model="data1" v-model:inputValue="inputValue"></lay-tag-input> <lay-tag-input v-model="data1" v-model:inputValue="inputValue1"></lay-tag-input>
</template> </template>
<script> <script>
@ -22,17 +22,65 @@ import { ref,watch } from 'vue'
export default { export default {
setup() { setup() {
const data1 = ref(['Vue', 'React']); const data1 = ref(['Vue', 'React']);
const inputValue = ref(); const inputValue1 = ref("");
watch(data1, (val) => {
console.log("tagData",val)
})
watch(inputValue, (val) => {
console.log("inputValue",val)
})
return { return {
data1, data1,
inputValue inputValue1
}
}
}
</script>
:::
::: title 只读状态
:::
::: demo 使用 `lay-tag-input` 标签, 创建标签输入框。
<template>
<lay-tag-input v-model="data3" v-model:inputValue="inputValue3" :readonly="true"></lay-tag-input>
</template>
<script>
import { ref,watch } from 'vue'
export default {
setup() {
const data3 = ref(['Vue', 'React']);
const inputValue3 = ref("");
return {
data3,
inputValue3
}
}
}
</script>
:::
::: title 禁用状态
:::
::: demo 使用 `lay-tag-input` 标签, 创建标签输入框。
<template>
<lay-tag-input v-model="data4" v-model:inputValue="inputValue4" :disabled="true"></lay-tag-input>
</template>
<script>
import { ref,watch } from 'vue'
export default {
setup() {
const data4 = ref(['Vue', 'React']);
const inputValue4 = ref("");
return {
data4,
inputValue4
} }
} }
} }

View File

@ -3,6 +3,7 @@ export default {
name: "TreadIcon", name: "TreadIcon",
}; };
</script> </script>
<script setup lang="ts"> <script setup lang="ts">
import LayIcon from "../component/icon/index"; import LayIcon from "../component/icon/index";
@ -11,6 +12,7 @@ const props = defineProps<{
size?: string; size?: string;
}>(); }>();
</script> </script>
<template> <template>
<lay-icon :color="props.color" :size="props.size" type="layui-icon-tread" /> <lay-icon :color="props.color" :size="props.size" type="layui-icon-tread" />
</template> </template>