Skip to content

Commit

Permalink
feat: add prepend-inner slot support to VXSelect component for custom…
Browse files Browse the repository at this point in the history
… item rendering
  • Loading branch information
danni-cool committed Feb 25, 2025
1 parent fcac822 commit 0a5011b
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 66 deletions.
146 changes: 81 additions & 65 deletions ui/vuetifyx/vuetifyxjs/docs/Components/VXSelect/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,33 @@

### Slot

#### v-slot:prepend-inner

可以自定义input文字前固定位置的图标的插槽

slot scope

```js
{
isActive: Ref<boolean>
isFocused: Ref<boolean>
controlRef: Ref<HTMLElement | undefined>
focus: () => void
blur: () => void
}
```

#### v-slot:item

每一项的插槽,用来自定义渲染每一项,根元素必须使用 `v-list-item` 及绑定上 `v-bind="props"`

slot scope
```
slot scope

```js
{ item: ListItem; index: number; props: Record<string, unknown> }
```
[example](#slot-item)

[example](#slot-item)

## 示例(vx-select)

Expand Down Expand Up @@ -149,14 +167,14 @@ const srcs = {
5: 'https://cdn.vuetifyjs.com/images/lists/5.jpg'
}
const items = ref([
{ id: 1, name: 'Sandra Adams', group: 'Group 1', avatar: srcs[1], icon:"mdi-wifi" },
{ id: 2, name: 'Ali Connors', group: 'Group 1', avatar: srcs[2], icon:"mdi-wifi" },
{ id: 3, name: 'Trevor Hansen', group: 'Group 1', avatar: srcs[3], icon:"mdi-wifi" },
{ id: 4, name: 'Tucker Smith', group: 'Group 1', avatar: srcs[2], icon:"mdi-wifi" },
{ id: 5, name: 'Britta Holt', group: 'Group 2', avatar: srcs[4], icon:"mdi-wifi" },
{ id: 6, name: 'Jane Smith ', group: 'Group 2', avatar: srcs[5], icon:"mdi-wifi" },
{ id: 7, name: 'John Smith', group: 'Group 2', avatar: srcs[1], icon:"mdi-wifi" },
{ id: 8, name: 'Sandra Williams', group: 'Group 2', avatar: srcs[3], icon:"mdi-wifi" }
{ id: 1, name: 'Sandra Adams', group: 'Group 1', avatar: srcs[1], icon: 'mdi-wifi' },
{ id: 2, name: 'Ali Connors', group: 'Group 1', avatar: srcs[2], icon: 'mdi-wifi' },
{ id: 3, name: 'Trevor Hansen', group: 'Group 1', avatar: srcs[3], icon: 'mdi-wifi' },
{ id: 4, name: 'Tucker Smith', group: 'Group 1', avatar: srcs[2], icon: 'mdi-wifi' },
{ id: 5, name: 'Britta Holt', group: 'Group 2', avatar: srcs[4], icon: 'mdi-wifi' },
{ id: 6, name: 'Jane Smith ', group: 'Group 2', avatar: srcs[5], icon: 'mdi-wifi' },
{ id: 7, name: 'John Smith', group: 'Group 2', avatar: srcs[1], icon: 'mdi-wifi' },
{ id: 8, name: 'Sandra Williams', group: 'Group 2', avatar: srcs[3], icon: 'mdi-wifi' }
])
</script>
Expand All @@ -165,68 +183,68 @@ const items = ref([

:::


### Slot(item)

item 的原始数据在 item.raw 里

:::demo

```vue
<template>
<vx-select
type="autocomplete"
v-model="valueAutoComplete"
multiple
chips
clearable
error-messages="error message"
label="autoComplete Select(state with error)"
:items="items"
item-title="name"
item-value="id"
placeholder="choose a item"
closable-chips
>
<template v-slot:item="{ props, item }">
<v-list-item
v-bind="props"
:title="item.title"
<div class="mb-4">1. item with prepend element + prepend inner element</div>
<v-row>
<v-col cols="6">
<vx-select
type="autocomplete"
v-model="valueAutoComplete"
label="autoComplete Select"
:items="items"
item-title="name"
item-value="id"
placeholder="choose a item"
closable-chips
>
<template v-slot:prepend>
<v-icon :icon="item.raw.icon"></v-icon>
<template v-slot:prepend-inner="{ selectedItems }">
<v-icon :icon="selectedItems[0].icon" />
</template>
</v-list-item>
</template>
</vx-select>
<vx-select
v-model="valueNormal"
label="Normal Select"
:items="items"
item-title="name"
item-value="id"
placeholder="choose a item"
>
<template v-slot:item="{ props, item }">
<v-list-item
v-bind="props"
:title="item.title"
<template v-slot:item="{ props, item }">
<v-list-item v-bind="props" :title="item.title">
<template v-slot:prepend>
<v-icon :icon="item.raw.icon" />
</template>
</v-list-item>
</template> </vx-select
></v-col>
<v-col cols="6">
<vx-select
v-model="valueNormal"
label="Normal Select"
:items="items"
item-title="name"
item-value="id"
placeholder="choose a item"
>
<template v-slot:prepend>
<v-icon :icon="item.raw.icon"></v-icon>
<template v-slot:prepend-inner="{ selectedItems }">
<v-icon :icon="selectedItems[0].icon" />
</template>
</v-list-item>
</template>
</vx-select>
<template v-slot:item="{ props, item }">
<v-list-item v-bind="props" :title="item.title">
<template v-slot:prepend>
<v-icon :icon="item.raw.icon" />
</template>
</v-list-item>
</template>
</vx-select>
</v-col>
</v-row>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const valueAutoComplete = ref([1, 2, 3])
const valueAutoComplete = ref([1])
const valueNormal = ref([1])
const valueWithErrorMsg = ref([1])
const srcs = {
Expand All @@ -237,24 +255,22 @@ const srcs = {
5: 'https://cdn.vuetifyjs.com/images/lists/5.jpg'
}
const items = ref([
{ id: 1, name: 'Sandra Adams', group: 'Group 1', avatar: srcs[1], icon:"mdi-wifi" },
{ id: 2, name: 'Ali Connors', group: 'Group 1', avatar: srcs[2], icon:"mdi-wifi" },
{ id: 3, name: 'Trevor Hansen', group: 'Group 1', avatar: srcs[3], icon:"mdi-wifi" },
{ id: 4, name: 'Tucker Smith', group: 'Group 1', avatar: srcs[2], icon:"mdi-wifi" },
{ id: 5, name: 'Britta Holt', group: 'Group 2', avatar: srcs[4], icon:"mdi-wifi" },
{ id: 6, name: 'Jane Smith ', group: 'Group 2', avatar: srcs[5], icon:"mdi-wifi" },
{ id: 7, name: 'John Smith', group: 'Group 2', avatar: srcs[1], icon:"mdi-wifi" },
{ id: 8, name: 'Sandra Williams', group: 'Group 2', avatar: srcs[3], icon:"mdi-wifi" }
{ id: 1, name: 'Sandra Adams', group: 'Group 1', avatar: srcs[1], icon: 'mdi-wifi' },
{ id: 2, name: 'Ali Connors', group: 'Group 1', avatar: srcs[2], icon: 'mdi-plus' },
{ id: 3, name: 'Trevor Hansen', group: 'Group 1', avatar: srcs[3], icon: 'mdi-information' },
{ id: 4, name: 'Tucker Smith', group: 'Group 1', avatar: srcs[2], icon: 'mdi-alert' },
{ id: 5, name: 'Britta Holt', group: 'Group 2', avatar: srcs[4], icon: 'mdi-alert-circle' },
{ id: 6, name: 'Jane Smith ', group: 'Group 2', avatar: srcs[5], icon: 'mdi-domain' },
{ id: 7, name: 'John Smith', group: 'Group 2', avatar: srcs[1], icon: 'mdi-message-text' },
{ id: 8, name: 'Sandra Williams', group: 'Group 2', avatar: srcs[3], icon: 'mdi-dialpad' }
])
</script>
<style scoped></style>
```

:::


## 示例(vx-selectmany)

> legacy component
Expand Down
45 changes: 44 additions & 1 deletion ui/vuetifyx/vuetifyxjs/src/lib/Form/VXSelect.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,21 @@
color="primary"
@update:model-value="onUpdateModelValue"
>
<template
v-if="hasPrependInnerSlot"
#prepend-inner="{ isActive, isFocused, controlRef, focus, blur }"
>
<slot
name="prepend-inner"
:isActive="isActive"
:isFocused="isFocused"
:controlRef="controlRef"
:focus="focus"
:blur="blur"
:selectedItems="selectedItems"
/>
</template>

<template v-if="hasItemSlot" #item="{ props, index, item }">
<slot name="item" :props="props" :index="index" :item="item" />
</template>
Expand All @@ -49,6 +64,21 @@
color="primary"
@update:model-value="onUpdateModelValue"
>
<template
v-if="hasPrependInnerSlot"
#prepend-inner="{ isActive, isFocused, controlRef, focus, blur }"
>
<slot
name="prepend-inner"
:isActive="isActive"
:isFocused="isFocused"
:controlRef="controlRef"
:focus="focus"
:blur="blur"
:selectedItems="selectedItems"
/>
</template>

<template v-if="hasItemSlot" #item="{ props, index, item }">
<slot name="item" :props="props" :index="index" :item="item" />
</template>
Expand All @@ -57,13 +87,14 @@
</template>

<script setup lang="ts">
import { defineEmits, ref, watch, PropType, useSlots, Slots } from 'vue'
import { defineEmits, ref, watch, PropType, useSlots, Slots, computed } from 'vue'
import VXLabel from '../Common/VXLabel.vue'
import { useFilteredAttrs } from '@/lib/composables/useFilteredAttrs'
const { filteredAttrs } = useFilteredAttrs()
const emit = defineEmits(['update:modelValue'])
const slots: Slots = useSlots()
const hasPrependInnerSlot = slots['prepend-inner'] !== undefined
const hasItemSlot = slots['item'] !== undefined
const props = defineProps({
modelValue: null,
Expand All @@ -88,6 +119,18 @@ const props = defineProps({
const selectValue = ref(props.modelValue)
const selectedItems = computed(() => {
return props.items?.filter((item: any) => {
if (props.multiple) {
return selectValue.value?.includes(props.itemValue ? item[props.itemValue] : item)
}
return Array.isArray(selectValue.value)
? selectValue.value[0] === (props.itemValue ? item[props.itemValue] : item)
: selectValue.value === (props.itemValue ? item[props.itemValue] : item)
})
})
watch(
() => props.modelValue,
(newVal) => (selectValue.value = newVal)
Expand Down

0 comments on commit 0a5011b

Please sign in to comment.