优化下拉框

This commit is contained in:
xuliangzhan
2023-12-24 18:36:43 +08:00
parent a52adf33e6
commit 153b2b91da
12 changed files with 171 additions and 29 deletions

View File

@@ -5,6 +5,23 @@
<p>
<vxe-select v-model="demo1.value10" placeholder="默认尺寸">
<template #header>
<div>
<vxe-button type="text">按钮</vxe-button>
<vxe-button type="text">按钮</vxe-button>
<vxe-button type="text">按钮</vxe-button>
<vxe-button type="text">按钮</vxe-button>
</div>
</template>
<template #footer>
<div>
<vxe-button type="text">按钮</vxe-button>
<vxe-button type="text">按钮</vxe-button>
<vxe-button type="text">按钮</vxe-button>
<vxe-button type="text">按钮</vxe-button>
</div>
</template>
<vxe-option v-for="num in 15" :key="num" :value="num" :label="`选项${num}`"></vxe-option>
</vxe-select>
<vxe-select v-model="demo1.value11" placeholder="中等尺寸" size="medium">
@@ -23,6 +40,23 @@
<vxe-option v-for="num in 3" :key="num" :value="num" :label="`选项${num}`"></vxe-option>
</vxe-select>
<vxe-select v-model="demo1.value21" placeholder="可搜索" filterable clearable>
<template #header>
<div>
<vxe-button type="text">按钮</vxe-button>
<vxe-button type="text">按钮</vxe-button>
<vxe-button type="text">按钮</vxe-button>
<vxe-button type="text">按钮</vxe-button>
</div>
</template>
<template #footer>
<div>
<vxe-button type="text">按钮</vxe-button>
<vxe-button type="text">按钮</vxe-button>
<vxe-button type="text">按钮</vxe-button>
<vxe-button type="text">按钮</vxe-button>
</div>
</template>
<vxe-option v-for="num in 11" :key="num" :value="num" :label="`选项${num}`"></vxe-option>
</vxe-select>
<vxe-select v-model="demo1.value24" placeholder="远程搜索" filterable clearable remote :remote-method="remoteMethod24">

View File

@@ -65,7 +65,7 @@
"sass": "^1.56.1",
"sass-loader": "^12.0.0",
"typescript": "~4.5.5",
"vue": "^3.3.4",
"vue": "^3.3.13",
"vue-i18n": "^9.1.7",
"vue-router": "^4.0.11",
"vuex": "^4.0.2"

View File

@@ -1,4 +1,4 @@
import { defineComponent, h, Teleport, ref, Ref, onUnmounted, reactive, nextTick, PropType, watch } from 'vue'
import { defineComponent, h, Teleport, ref, Ref, onUnmounted, reactive, nextTick, PropType, watch, createCommentVNode } from 'vue'
import XEUtils from 'xe-utils'
import GlobalConfig from '../../v-x-e-table/src/conf'
import { useSize } from '../../hooks/size'
@@ -281,6 +281,10 @@ export default defineComponent({
const { className, popupClassName, destroyOnClose, transfer, disabled } = props
const { inited, isActivated, animatVisible, visiblePanel, panelStyle, panelPlacement } = reactData
const vSize = computeSize.value
const defaultSlot = slots.default
const headerSlot = slots.header
const footerSlot = slots.footer
const dropdownSlot = slots.dropdown
return h('div', {
ref: refElem,
class: ['vxe-pulldown', className ? (XEUtils.isFunction(className) ? className({ $pulldown: $xepulldown }) : className) : '', {
@@ -293,7 +297,7 @@ export default defineComponent({
h('div', {
ref: refPulldowContent,
class: 'vxe-pulldown--content'
}, slots.default ? slots.default({ $pulldown: $xepulldown }) : []),
}, defaultSlot ? defaultSlot({ $pulldown: $xepulldown }) : []),
h(Teleport, {
to: 'body',
disabled: transfer ? !inited : true
@@ -308,10 +312,20 @@ export default defineComponent({
}],
placement: panelPlacement,
style: panelStyle
}, slots.dropdown ? [
}, dropdownSlot ? [
h('div', {
class: 'vxe-pulldown--wrapper'
}, !inited || (destroyOnClose && !visiblePanel && !animatVisible) ? [] : slots.dropdown({ $pulldown: $xepulldown }))
class: 'vxe-pulldown--panel-wrapper'
}, !inited || (destroyOnClose && !visiblePanel && !animatVisible) ? [] : [
headerSlot ? h('div', {
class: 'vxe-pulldown--panel-header'
}, headerSlot({ $pulldown: $xepulldown })) : createCommentVNode(),
h('div', {
class: 'vxe-pulldown--panel-body'
}, dropdownSlot({ $pulldown: $xepulldown })),
footerSlot ? h('div', {
class: 'vxe-pulldown--panel-footer'
}, footerSlot({ $pulldown: $xepulldown })) : createCommentVNode()
])
] : [])
])
])

View File

@@ -716,6 +716,7 @@ export default defineComponent({
const valueField = computeValueField.value
const isGroup = computeIsGroup.value
const { useKey } = optionOpts
const optionSlot = slots.option
return list.map((option, cIndex) => {
const { slots, className } = option
const optionValue = option[valueField as 'value']
@@ -724,9 +725,10 @@ export default defineComponent({
const isDisabled = checkOptionDisabled(isSelected, option, group)
const optid = getOptid(option)
const defaultSlot = slots ? slots.default : null
const optParams = { option, group: null, $select: $xeselect }
return isVisible ? h('div', {
key: useKey || optionKey ? optid : cIndex,
class: ['vxe-select-option', className ? (XEUtils.isFunction(className) ? className({ option, $select: $xeselect }) : className) : '', {
class: ['vxe-select-option', className ? (XEUtils.isFunction(className) ? className(optParams) : className) : '', {
'is--disabled': isDisabled,
'is--selected': isSelected,
'is--hover': currentValue === optionValue
@@ -750,7 +752,7 @@ export default defineComponent({
setCurrentOption(option)
}
}
}, defaultSlot ? callSlot(defaultSlot, { option, $select: $xeselect }) : formatText(getFuncText(option[labelField as 'label']))) : null
}, optionSlot ? callSlot(optionSlot, optParams) : (defaultSlot ? callSlot(defaultSlot, optParams) : formatText(getFuncText(option[labelField as 'label'])))) : null
})
}
@@ -761,14 +763,16 @@ export default defineComponent({
const groupLabelField = computeGroupLabelField.value
const groupOptionsField = computeGroupOptionsField.value
const { useKey } = optionOpts
const optionSlot = slots.option
return visibleGroupList.map((group, gIndex) => {
const { slots, className } = group
const optid = getOptid(group)
const isGroupDisabled = group.disabled
const defaultSlot = slots ? slots.default : null
const optParams = { option: group, group, $select: $xeselect }
return h('div', {
key: useKey || optionKey ? optid : gIndex,
class: ['vxe-optgroup', className ? (XEUtils.isFunction(className) ? className({ option: group, $select: $xeselect }) : className) : '', {
class: ['vxe-optgroup', className ? (XEUtils.isFunction(className) ? className(optParams) : className) : '', {
'is--disabled': isGroupDisabled
}],
// attrs
@@ -776,7 +780,7 @@ export default defineComponent({
}, [
h('div', {
class: 'vxe-optgroup--title'
}, defaultSlot ? callSlot(defaultSlot, { option: group, $select: $xeselect }) : getFuncText(group[groupLabelField as 'label'])),
}, optionSlot ? callSlot(optionSlot, optParams) : (defaultSlot ? callSlot(defaultSlot, optParams) : getFuncText(group[groupLabelField as 'label']))),
h('div', {
class: 'vxe-optgroup--wrapper'
}, renderOption(group[groupOptionsField as 'options'] || [], group))
@@ -912,6 +916,9 @@ export default defineComponent({
const { inited, isActivated, visiblePanel } = reactData
const vSize = computeSize.value
const selectLabel = computeSelectLabel.value
const defaultSlot = slots.default
const headerSlot = slots.header
const footerSlot = slots.footer
const prefixSlot = slots.prefix
return h('div', {
ref: refElem,
@@ -927,7 +934,7 @@ export default defineComponent({
h('div', {
class: 'vxe-select-slots',
ref: 'hideOption'
}, slots.default ? slots.default({}) : []),
}, defaultSlot ? defaultSlot({}) : []),
h(VxeInputComponent, {
ref: refInput,
clearable: props.clearable,
@@ -962,11 +969,11 @@ export default defineComponent({
style: reactData.panelStyle
}, inited ? [
filterable ? h('div', {
class: 'vxe-select-filter--wrapper'
class: 'vxe-select--panel-search'
}, [
h(VxeInputComponent, {
ref: refInpSearch,
class: 'vxe-select-filter--input',
class: 'vxe-select-search--input',
modelValue: reactData.searchValue,
clearable: true,
placeholder: GlobalConfig.i18n('vxe.select.search'),
@@ -979,9 +986,23 @@ export default defineComponent({
})
]) : createCommentVNode(),
h('div', {
ref: refOptionWrapper,
class: 'vxe-select-option--wrapper'
}, renderOpts())
class: 'vxe-select--panel-wrapper'
}, [
headerSlot ? h('div', {
class: 'vxe-select--panel-header'
}, headerSlot({})) : createCommentVNode(),
h('div', {
class: 'vxe-select--panel-body'
}, [
h('div', {
ref: refOptionWrapper,
class: 'vxe-select-option--wrapper'
}, renderOpts())
]),
footerSlot ? h('div', {
class: 'vxe-select--panel-footer'
}, footerSlot({})) : createCommentVNode()
])
] : [])
])
])

View File

@@ -14,7 +14,7 @@ const GlobalConfig: VXETableConfigOptions = {
showHeader: true,
animat: true,
delayHover: 250,
autoResize: false,
autoResize: true,
minHeight: 144,
// keepSource: false,
// showOverflow: null,

View File

@@ -38,7 +38,7 @@
transform: scaleY(1);
}
}
.vxe-pulldown--wrapper {
.vxe-pulldown--panel-wrapper {
background-color: var(--vxe-pulldown-panel-background-color);
}

View File

@@ -79,23 +79,40 @@
}
}
.vxe-select-filter--wrapper {
.vxe-select--panel-search {
display: block;
.vxe-select-filter--input {
.vxe-select-search--input {
width: 100%;
}
}
.vxe-select--panel-wrapper {
position: relative;
border-radius: var(--vxe-border-radius);
border: 1px solid var(--vxe-table-popup-border-color);
box-shadow: 0 0 6px 2px rgba(0, 0, 0, 0.1);
background-color: var(--vxe-select-panel-background-color);
}
.vxe-select--panel-header {
border-bottom: 1px solid var(--vxe-table-popup-border-color);
}
.vxe-select--panel-footer {
border-top: 1px solid var(--vxe-table-popup-border-color);
}
.vxe-select--panel-header,
.vxe-select--panel-footer {
padding: 4px 0;
}
.vxe-select-option--wrapper {
position: relative;
overflow-x: hidden;
overflow-y: auto;
padding: 4px 0;
max-height: 200px;
border-radius: var(--vxe-border-radius);
border: 1px solid var(--vxe-table-popup-border-color);
box-shadow: 0 0 6px 2px rgba(0, 0, 0, 0.1);
background-color: var(--vxe-select-panel-background-color);
}
.vxe-optgroup {

17
types/column.d.ts vendored
View File

@@ -181,11 +181,11 @@ export namespace VxeColumnPropTypes {
/**
* 只对 type=radio 有效,自定义单选框模板
*/
radio?: string | ((params: VxeColumnSlotTypes.DefaultSlotParams<D>) => SlotVNodeType[] | SlotVNodeType) | null
radio?: string | ((params: VxeColumnSlotTypes.RadioSlotParams<D>) => SlotVNodeType[] | SlotVNodeType) | null
/**
* 只对 type=checkbox 有效,自定义复选框模板
*/
checkbox?: string | ((params: VxeColumnSlotTypes.DefaultSlotParams<D>) => SlotVNodeType[] | SlotVNodeType) | null
checkbox?: string | ((params: VxeColumnSlotTypes.CheckboxSlotParams<D>) => SlotVNodeType[] | SlotVNodeType) | null
/**
* 自定义显示内容模板
*/
@@ -405,7 +405,7 @@ export namespace VxeColumnSlotTypes {
data: D[][]
}
export interface HeaderSlotParams<D = VxeTableDataRow> extends VxeTableDefines.CellRenderHeaderParams<D> { }
export interface HeaderSlotParams<D = VxeTableDataRow> extends VxeTableDefines.CellRenderHeaderParams<D> {}
export interface ContentSlotParams<D = VxeTableDataRow> {
column: VxeTableDefines.ColumnInfo<D>
@@ -421,6 +421,13 @@ export namespace VxeColumnSlotTypes {
export interface DefaultSlotParams<D = VxeTableDataRow> extends VxeTableDefines.CellRenderBodyParams<D> { }
export interface CheckboxSlotParams<D = VxeTableDataRow> extends DefaultSlotParams<D> {
checked: boolean
indeterminate: boolean
}
export interface RadioSlotParams<D = VxeTableDataRow> extends DefaultSlotParams<D> {
checked: boolean
}
export interface IconSlotParams<D = VxeTableDataRow> extends DefaultSlotParams<D> { }
}
@@ -444,11 +451,11 @@ export interface VxeColumnSlots<D = VxeTableDataRow> {
/**
* 只对 type=checkbox 有效,自定义复选框模板
*/
checkbox: (params: VxeColumnSlotTypes.DefaultSlotParams<D>) => any
checkbox: (params: VxeColumnSlotTypes.CheckboxSlotParams<D>) => any
/**
* 只对 type=radio 有效,自定义单选框模板
*/
radio: (params: VxeColumnSlotTypes.DefaultSlotParams<D>) => any
radio: (params: VxeColumnSlotTypes.RadioSlotParams<D>) => any
/**
* 只对 type=expand 有效,自定义展开后的内容模板
*/

5
types/grid.d.ts vendored
View File

@@ -593,6 +593,11 @@ export interface VxeGridSlots<D = VxeTableDataRow> {
$columnIndex: number
_columnIndex: number
checked?: boolean
indeterminate?: boolean
items: D[]
[key: string]: any
}) => any) | undefined
}

12
types/pulldown.d.ts vendored
View File

@@ -126,12 +126,24 @@ export interface VxePulldownListeners {
}
export interface VxePulldownSlots {
/**
* 自定义弹窗容器头部模板
*/
header: (params: {
[key: string]: any
}) => any
/**
* 自定义显示的内容
*/
default: (params: {
[key: string]: any
}) => any
/**
* 自定义弹窗容器底部模板
*/
footer: ((params: {
[key: string]: any
}) => any) | undefined
/**
* 自定义下拉面板显示的内容
*/

29
types/select.d.ts vendored
View File

@@ -232,10 +232,39 @@ export namespace VxeSelectEvents {
}
export interface VxeSelectSlots {
/**
* 自定义前缀图标模板
*/
prefix: (params: {
[key: string]: any
}) => any
/**
* 自定义弹窗容器头部模板
*/
header: (params: {
[key: string]: any
}) => any
/**
* 自定义弹窗容器选项模板
*/
option: ((params: {
option: any
group: any
[key: string]: any
}) => any) | undefined
/**
* 自定义弹窗容器底部模板
*/
footer: ((params: {
[key: string]: any
}) => any) | undefined
/**
* 自定义插槽模板
*/
[key: string]: ((params: {
option: any
group: any
[key: string]: any
}) => any) | undefined
}

3
types/table.d.ts vendored
View File

@@ -2892,6 +2892,9 @@ export namespace VxeTableDefines {
type: string
isHidden: boolean
hasFilter: boolean
checked?: boolean
indeterminate?: boolean
}
export interface CellRenderBodyParams<D = VxeTableDataRow> {