mirror of
https://github.com/element-plus/element-plus.git
synced 2025-08-26 12:32:17 +08:00
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:
@ -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
|
## Grouping
|
||||||
|
|
||||||
Display options in groups.
|
Display options in groups.
|
||||||
@ -184,11 +204,13 @@ select/value-key
|
|||||||
|
|
||||||
### Select Slots
|
### Select Slots
|
||||||
|
|
||||||
| Name | Description | Subtags |
|
| Name | Description | Subtags |
|
||||||
| ------- | -------------------------------- | --------------------- |
|
| ------- | ------------------------------------- | --------------------- |
|
||||||
| default | option component list | Option Group / Option |
|
| default | option component list | Option Group / Option |
|
||||||
| prefix | content as Select prefix | — |
|
| header ^(2.4.3) | content at the top of the dropdown | — |
|
||||||
| empty | content when there is no options | — |
|
| 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
|
### Select Exposes
|
||||||
|
|
||||||
|
89
docs/examples/select/custom-footer.vue
Normal file
89
docs/examples/select/custom-footer.vue
Normal 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>
|
93
docs/examples/select/custom-header.vue
Normal file
93
docs/examples/select/custom-header.vue
Normal 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>
|
@ -3,7 +3,13 @@
|
|||||||
:class="[ns.b('dropdown'), ns.is('multiple', isMultiple), popperClass]"
|
:class="[ns.b('dropdown'), ns.is('multiple', isMultiple), popperClass]"
|
||||||
:style="{ [isFitInputWidth ? 'width' : 'minWidth']: minWidth }"
|
:style="{ [isFitInputWidth ? 'width' : 'minWidth']: minWidth }"
|
||||||
>
|
>
|
||||||
|
<div v-if="$slots.header" :class="ns.be('dropdown', 'header')">
|
||||||
|
<slot name="header" />
|
||||||
|
</div>
|
||||||
<slot />
|
<slot />
|
||||||
|
<div v-if="$slots.footer" :class="ns.be('dropdown', 'footer')">
|
||||||
|
<slot name="footer" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -249,6 +249,9 @@
|
|||||||
</template>
|
</template>
|
||||||
<template #content>
|
<template #content>
|
||||||
<el-select-menu>
|
<el-select-menu>
|
||||||
|
<template v-if="$slots.header" #header>
|
||||||
|
<slot name="header" />
|
||||||
|
</template>
|
||||||
<el-scrollbar
|
<el-scrollbar
|
||||||
v-show="options.size > 0 && !loading"
|
v-show="options.size > 0 && !loading"
|
||||||
:id="contentId"
|
:id="contentId"
|
||||||
@ -277,6 +280,9 @@
|
|||||||
{{ emptyText }}
|
{{ emptyText }}
|
||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
|
<template v-if="$slots.footer" #footer>
|
||||||
|
<slot name="footer" />
|
||||||
|
</template>
|
||||||
</el-select-menu>
|
</el-select-menu>
|
||||||
</template>
|
</template>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
|
@ -442,6 +442,8 @@ $select-dropdown: map.merge(
|
|||||||
'max-height': 274px,
|
'max-height': 274px,
|
||||||
'padding': 6px 0,
|
'padding': 6px 0,
|
||||||
'empty-padding': 10px 0,
|
'empty-padding': 10px 0,
|
||||||
|
'header-padding': 10px,
|
||||||
|
'footer-padding': 10px,
|
||||||
'border': 1px solid getCssVar('border-color-light'),
|
'border': 1px solid getCssVar('border-color-light'),
|
||||||
),
|
),
|
||||||
$select-dropdown
|
$select-dropdown
|
||||||
|
@ -89,3 +89,13 @@ $checked-icon: "data:image/svg+xml;utf8,%3Csvg class='icon' width='200' height='
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
box-sizing: border-box;
|
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');
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user