!43 select组件优化

Merge pull request !43 from 鄢鹏权/develop
This commit is contained in:
就眠儀式 2022-04-03 12:00:08 +00:00 committed by Gitee
commit 4c653112a2
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
3 changed files with 201 additions and 34 deletions

View File

@ -4,7 +4,7 @@
::: title 基本介绍 ::: title 基本介绍
::: :::
::: describe 用于代替原生的选择器,或者需要一个更优雅的多选器时。 ::: describe 用于代替原生的选择器,或者需要一个更优雅的多选器时。支持关键词查询
::: :::
::: title 基础使用 ::: title 基础使用
@ -40,10 +40,10 @@ export default {
::: demo ::: demo
<template> <template>
<lay-button @click="change1">切换-当前值 : {{value}}</lay-button> <lay-button @click="change1">切换-当前值 : {{value2}}</lay-button>
<br/> <br/>
<br/> <br/>
<lay-select v-model="value"> <lay-select v-model="value2">
<lay-select-option value="1" label="学习"></lay-select-option> <lay-select-option value="1" label="学习"></lay-select-option>
<lay-select-option value="2" label="编码"></lay-select-option> <lay-select-option value="2" label="编码"></lay-select-option>
<lay-select-option value="3" label="运动"></lay-select-option> <lay-select-option value="3" label="运动"></lay-select-option>
@ -55,13 +55,13 @@ import { ref } from 'vue'
export default { export default {
setup() { setup() {
const value = ref(null); const value2 = ref(null);
var i = 1; var i = 1;
function change1(){ function change1(){
value.value=i++%3+1 value2.value=i++%3+1
} }
return { return {
value, value2,
change1 change1
} }
} }
@ -100,13 +100,141 @@ export default {
::: :::
::: title 海量数据 ::: title 关键词变化事件,可作为远程搜索处理算法
:::
::: demo
<template>
<lay-select @search="search" v-model="selected">
<lay-select-option value="1" label="学习"></lay-select-option>
<lay-select-option value="2" label="编码" disabled></lay-select-option>
<lay-select-option value="3" label="运动"></lay-select-option>
</lay-select>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const selected = ref('1');
function search(txt){
console.log('关键词:',txt)
}
return {
selected,search
}
}
}
</script>
:::
::: title 选择项自定义搜索内容可以在keyword属性中传入拼音用于支持拼音搜索
::: :::
::: demo ::: demo
<template> <template>
<lay-select v-model="selected"> <lay-select v-model="selected">
<lay-select-option value="1" label="学习" keyword="学习xuexi"></lay-select-option>
<lay-select-option value="2" label="编码" disabled></lay-select-option>
<lay-select-option value="3" label="运动"></lay-select-option>
</lay-select>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const selected = ref('1');
return {
selected
}
}
}
</script>
:::
::: title 传入items属性进行选项渲染
:::
::: demo
<template>
<lay-select v-model="selected" :items="items">
</lay-select>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const selected = ref('1');
const items=ref([
{label:'选项1',value:1,keyword:'选项xuanxiang1'},
{label:'选项2',value:2,keyword:'选项xuanxiang2'},
{label:'选项3',value:3,keyword:'选项xuanxiang3',disabled:true},
])
return {
selected,items
}
}
}
</script>
:::
::: title 传入create属性和接收create事件用于开启创建子项功能
:::
::: demo
<template>
<lay-select v-model="selected" :items="items" :create="true" @create="createEvent">
</lay-select>
当前元素: {{items.map(o=>o.label).join()}}
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const selected = ref('1');
const items=ref([
{label:'选项1',value:'1',keyword:'选项xuanxiang1'},
{label:'选项2',value:2,keyword:'选项xuanxiang2'},
{label:'选项3',value:3,keyword:'选项xuanxiang3',disabled:true},
]);
function createEvent(v){
items.value.push({
label:v,
value:items.value.length
})
}
return {
selected,items,createEvent
}
}
}
</script>
:::
::: title 海量数据
:::
::: demo
<template>
<lay-select v-model="selected2">
<lay-select-option value="1" label="学习"></lay-select-option> <lay-select-option value="1" label="学习"></lay-select-option>
<lay-select-option value="3" label="运动"></lay-select-option> <lay-select-option value="3" label="运动"></lay-select-option>
<lay-select-option value="1" label="学习"></lay-select-option> <lay-select-option value="1" label="学习"></lay-select-option>
@ -132,10 +260,10 @@ import { ref } from 'vue'
export default { export default {
setup() { setup() {
const selected = ref('1') const selected2 = ref('1')
return { return {
selected selected2
} }
} }
} }
@ -193,6 +321,7 @@ export default {
| disabled | 是否禁用 | `boolean` | `true` `false` | `false` | | disabled | 是否禁用 | `boolean` | `true` `false` | `false` |
| showEmpty | 是否增加空提示选项 | `boolean` | `true` `false` | `true` | | showEmpty | 是否增加空提示选项 | `boolean` | `true` `false` | `true` |
| multiple | 是否为多选 | `boolean` | `true` `false` | `false` | | multiple | 是否为多选 | `boolean` | `true` `false` | `false` |
| create | 是否允许创建 | `boolean` | `true` `false` | `false` |
::: :::
@ -205,6 +334,8 @@ export default {
| 属性 | 描述 | 接收值 | | 属性 | 描述 | 接收值 |
| ------ | ---------- | --------------- | | ------ | ---------- | --------------- |
| change | 切换事件 | value | | change | 切换事件 | value |
| search | 关键词变化事件 | 用户输入的关键词 string |
| create | 允许创建情况下的创建回调事件 | 用户输入的关键词 string |
::: :::
@ -220,6 +351,7 @@ export default {
| ------------ | --------------------- | ------------------------- | -------------- | -------- | | ------------ | --------------------- | ------------------------- | -------------- | -------- |
| label | 标签值(`必填`) | `string` | - | - | | label | 标签值(`必填`) | `string` | - | - |
| value | 值 | `string` / `number` | - | - | | value | 值 | `string` / `number` | - | - |
| keyword | 用于匹配关键词的数据,传入文本+拼音可以支持拼音搜索 | `string` | - | - |
| disabled | 是否禁用 | `boolean` | `true` `false` | `false` | | disabled | 是否禁用 | `boolean` | `true` `false` | `false` |
::: :::

View File

@ -29,6 +29,8 @@ export interface LaySelectProps {
showEmpty?: boolean; showEmpty?: boolean;
emptyMessage?: string; emptyMessage?: string;
multiple?: boolean; multiple?: boolean;
create?: boolean;
items?: { label: string, value: string | number | [] | null, key: string }[]
} }
const selectRef = ref<null | HTMLElement>(null); const selectRef = ref<null | HTMLElement>(null);
@ -43,6 +45,7 @@ const props = withDefaults(defineProps<LaySelectProps>(), {
disabled: false, disabled: false,
showEmpty: true, showEmpty: true,
multiple: false, multiple: false,
create: false
}); });
const openState = ref(false); const openState = ref(false);
@ -54,9 +57,10 @@ const open = function () {
return; return;
} }
openState.value = !openState.value; openState.value = !openState.value;
console.log(props.create)
}; };
const emit = defineEmits(["update:modelValue", "change"]); const emit = defineEmits(["update:modelValue", "change", 'search', 'create']);
const selectItem = ref<SelectItem>({ const selectItem = ref<SelectItem>({
value: !props.multiple value: !props.multiple
? props.modelValue ? props.modelValue
@ -96,13 +100,31 @@ watch(props, () => {
// //
const disabledItemMap: { [key: string | number]: boolean } = {}; const disabledItemMap: { [key: string | number]: boolean } = {};
const selectItemHandle = function ( const txt = ref("")
const input = ref(false)
const value = computed({
set(v: any) {
txt.value = v;
emit('search', v)
},
get() {
if (input.value) {
return txt.value;
}
// return txt.value;
return !selectItem.value.multiple && selectItem.value.value !== null
? selectItem.value.label
: null
}
})
const selectItemHandle = async function (
_selectItem: SelectItem, _selectItem: SelectItem,
isChecked?: boolean isChecked?: boolean
) { ) {
if (!props.multiple) { if (!props.multiple) {
openState.value = false; openState.value = false;
} }
txt.value = ""
disabledItemMap[_selectItem.value as string | number] = disabledItemMap[_selectItem.value as string | number] =
_selectItem.disabled as boolean; _selectItem.disabled as boolean;
if (typeof isChecked !== "boolean") { if (typeof isChecked !== "boolean") {
@ -144,6 +166,7 @@ const selectItemPush = function (p: SelectItem) {
provide("selectItemHandle", selectItemHandle); provide("selectItemHandle", selectItemHandle);
provide("selectItemPush", selectItemPush); provide("selectItemPush", selectItemPush);
provide("selectItem", selectItem); provide("selectItem", selectItem);
provide("keyword", txt)
</script> </script>
<template> <template>
@ -163,12 +186,9 @@ provide("selectItem", selectItem);
: emptyMessage ?? placeholder : emptyMessage ?? placeholder
" "
:disabled="disabled" :disabled="disabled"
readonly v-model="value"
:value=" @input="input = true"
!selectItem.multiple && selectItem.value !== null @blur="input = false"
? selectItem.label
: null
"
:name="name" :name="name"
:class="[ :class="[
'layui-input', 'layui-input',
@ -204,8 +224,7 @@ provide("selectItem", selectItem);
: null, : null,
}) })
" "
> ></i>
</i>
</lay-badge> </lay-badge>
</template> </template>
</div> </div>
@ -214,9 +233,22 @@ provide("selectItem", selectItem);
<!-- 下拉内容 --> <!-- 下拉内容 -->
<dl class="layui-anim layui-anim-upbit"> <dl class="layui-anim layui-anim-upbit">
<template v-if="!multiple && showEmpty"> <template v-if="!multiple && showEmpty && !props.create">
<lay-select-option :value="null" :label="emptyMessage ?? placeholder" /> <lay-select-option :value="null" :label="emptyMessage ?? placeholder" />
</template> </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> <slot></slot>
</dl> </dl>
</div> </div>

View File

@ -7,21 +7,25 @@ export default {
<script setup lang="ts"> <script setup lang="ts">
import LayCheckbox from "../checkbox"; import LayCheckbox from "../checkbox";
import { SelectItem, SelectItemHandle, SelectItemPush } from "../../types"; import { SelectItem, SelectItemHandle, SelectItemPush } from "../../types";
import { computed, inject, onMounted, Ref } from "vue"; import { computed, inject, onMounted, Ref, ref } from "vue";
export interface LaySelectOptionProps { export interface LaySelectOptionProps {
value: string | null | undefined; value: string | null | undefined | number;
label?: string; label: string;
keyword?: string;
disabled?: boolean; disabled?: boolean;
} }
const props = withDefaults(defineProps<LaySelectOptionProps>(), { const props = withDefaults(defineProps<LaySelectOptionProps>(), {
disabled: false, disabled: false,
keyword: "",
label: ""
}); });
const selectItemHandle = inject("selectItemHandle") as SelectItemHandle; const selectItemHandle = inject("selectItemHandle") as SelectItemHandle;
const selectItem = inject("selectItem") as Ref<SelectItem>; const selectItem = inject("selectItem") as Ref<SelectItem>;
const selectItemPush = inject("selectItemPush") as Ref<SelectItemPush>; const selectItemPush = inject("selectItemPush") as Ref<SelectItemPush>;
const keyword = inject('keyword') as Ref<string>
const selectHandle = function () { const selectHandle = function () {
!props.disabled && callSelectItemHandle(!selected.value); !props.disabled && callSelectItemHandle(!selected.value);
@ -56,25 +60,24 @@ const callSelectItemPush = function () {
// @ts-ignore // @ts-ignore
selectItemPush(item); selectItemPush(item);
}; };
const search = ref("")
onMounted(() => { onMounted(() => {
search.value = props.keyword || props.label
callSelectItemPush(); callSelectItemPush();
selected.value && callSelectItemHandle(); selected.value && callSelectItemHandle();
}); });
</script> </script>
<template> <template>
<dd <dd
v-show="keyword ? search.includes(keyword) : true"
:value="value" :value="value"
:class="[{ 'layui-this': selected }, { 'layui-disabled': disabled }]" :class="[{ 'layui-this': selected }, { 'layui-disabled': disabled }]"
@click="selectHandle" @click="selectHandle"
> >
<template v-if="selectItem.multiple"> <template v-if="selectItem.multiple">
<lay-checkbox <lay-checkbox skin="primary" v-model="selected" @change="selectHandle" label />
skin="primary"
v-model="selected"
@change="selectHandle"
label=""
/>
</template> </template>
<slot>{{ label }}</slot> <slot>{{ label }}</slot>
</dd> </dd>