feat(components): [select] add header and footer slot (#14876)

* feat(components): [select] add header and footer slot

* fix(docs): [select] incorrect word

* fix(theme-chalk): [select-dropdown] incorrect padding

* Update docs/en-US/component/select.md

Co-authored-by: btea <2356281422@qq.com>

* Apply suggestions from code review

Co-authored-by: btea <2356281422@qq.com>

---------

Co-authored-by: qinzz <qinzz@chint.com>
Co-authored-by: btea <2356281422@qq.com>
This commit is contained in:
Cheerwhy 2023-11-27 15:26:48 +08:00 committed by GitHub
parent 4f347eeec6
commit f37d056441
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 233 additions and 5 deletions

View File

@ -69,6 +69,26 @@ select/custom-template
:::
## Header of the dropdown ^(2.4.3)
You can customize the header of the dropdown.
::: demo Use slot to customize the content.
select/custom-header
:::
## Footer of the dropdown ^(2.4.3)
You can customize the footer of the dropdown.
::: demo Use slot to customize the content.
select/custom-footer
:::
## Grouping
Display options in groups.
@ -184,11 +204,13 @@ select/value-key
### Select Slots
| Name | Description | Subtags |
| ------- | -------------------------------- | --------------------- |
| default | option component list | Option Group / Option |
| prefix | content as Select prefix | — |
| empty | content when there is no options | — |
| Name | Description | Subtags |
| ------- | ------------------------------------- | --------------------- |
| default | option component list | Option Group / Option |
| header ^(2.4.3) | content at the top of the dropdown | — |
| footer ^(2.4.3) | content at the bottom of the dropdown | — |
| prefix | content as Select prefix | — |
| empty | content when there is no options | — |
### Select Exposes

View File

@ -0,0 +1,89 @@
<template>
<el-select v-model="value" placeholder="Select">
<el-option
v-for="item in cities"
:key="item.value"
:label="item.label"
:value="item.value"
/>
<template #footer>
<el-button v-if="!isAdding" text bg size="small" @click="onAddOption">
Add an option
</el-button>
<template v-else>
<el-input
v-model="optionName"
class="option-input"
placeholder="input option name"
size="small"
/>
<el-button type="primary" size="small" @click="onConfirm">
confirm
</el-button>
<el-button size="small" @click="clear">cancel</el-button>
</template>
</template>
</el-select>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import type { CheckboxValueType } from 'element-plus'
const isAdding = ref(false)
const value = ref<CheckboxValueType[]>([])
const optionName = ref('')
const cities = ref([
{
value: 'Beijing',
label: 'Beijing',
},
{
value: 'Shanghai',
label: 'Shanghai',
},
{
value: 'Nanjing',
label: 'Nanjing',
},
{
value: 'Chengdu',
label: 'Chengdu',
},
{
value: 'Shenzhen',
label: 'Shenzhen',
},
{
value: 'Guangzhou',
label: 'Guangzhou',
},
])
const onAddOption = () => {
isAdding.value = true
}
const onConfirm = () => {
if (optionName.value) {
cities.value.push({
label: optionName.value,
value: optionName.value,
})
clear()
}
}
const clear = () => {
optionName.value = ''
isAdding.value = false
}
</script>
<style lang="scss" scoped>
.option-input {
width: 100%;
margin-bottom: 8px;
}
</style>

View File

@ -0,0 +1,93 @@
<template>
<el-select
v-model="value"
multiple
clearable
collapse-tags
placeholder="Select"
popper-class="custom-header"
:max-collapse-tags="1"
>
<template #header>
<el-checkbox
v-model="checkAll"
:indeterminate="indeterminate"
@change="handleCheckAll"
>
All
</el-checkbox>
</template>
<el-option
v-for="item in cities"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</template>
<script lang="ts" setup>
import { ref, watch } from 'vue'
import type { CheckboxValueType } from 'element-plus'
const checkAll = ref(false)
const indeterminate = ref(false)
const value = ref<CheckboxValueType[]>([])
const cities = ref([
{
value: 'Beijing',
label: 'Beijing',
},
{
value: 'Shanghai',
label: 'Shanghai',
},
{
value: 'Nanjing',
label: 'Nanjing',
},
{
value: 'Chengdu',
label: 'Chengdu',
},
{
value: 'Shenzhen',
label: 'Shenzhen',
},
{
value: 'Guangzhou',
label: 'Guangzhou',
},
])
watch(value, (val) => {
if (val.length === 0) {
checkAll.value = false
indeterminate.value = false
} else if (val.length === cities.value.length) {
checkAll.value = true
indeterminate.value = false
} else {
indeterminate.value = true
}
})
const handleCheckAll = (val: CheckboxValueType) => {
indeterminate.value = false
if (val) {
value.value = cities.value.map((_) => _.value)
} else {
value.value = []
}
}
</script>
<style lang="scss">
.custom-header {
.el-checkbox {
display: flex;
height: unset;
}
}
</style>

View File

@ -3,7 +3,13 @@
:class="[ns.b('dropdown'), ns.is('multiple', isMultiple), popperClass]"
:style="{ [isFitInputWidth ? 'width' : 'minWidth']: minWidth }"
>
<div v-if="$slots.header" :class="ns.be('dropdown', 'header')">
<slot name="header" />
</div>
<slot />
<div v-if="$slots.footer" :class="ns.be('dropdown', 'footer')">
<slot name="footer" />
</div>
</div>
</template>

View File

@ -249,6 +249,9 @@
</template>
<template #content>
<el-select-menu>
<template v-if="$slots.header" #header>
<slot name="header" />
</template>
<el-scrollbar
v-show="options.size > 0 && !loading"
:id="contentId"
@ -277,6 +280,9 @@
{{ emptyText }}
</p>
</template>
<template v-if="$slots.footer" #footer>
<slot name="footer" />
</template>
</el-select-menu>
</template>
</el-tooltip>

View File

@ -442,6 +442,8 @@ $select-dropdown: map.merge(
'max-height': 274px,
'padding': 6px 0,
'empty-padding': 10px 0,
'header-padding': 10px,
'footer-padding': 10px,
'border': 1px solid getCssVar('border-color-light'),
),
$select-dropdown

View File

@ -89,3 +89,13 @@ $checked-icon: "data:image/svg+xml;utf8,%3Csvg class='icon' width='200' height='
margin: 0;
box-sizing: border-box;
}
@include b(select-dropdown__header) {
padding: map.get($select-dropdown, 'header-padding');
border-bottom: map.get($select-dropdown, 'border');
}
@include b(select-dropdown__footer) {
padding: map.get($select-dropdown, 'footer-padding');
border-top: map.get($select-dropdown, 'border');
}