refactor(components): [segmented] make component generic

This commit is contained in:
rzzf
2026-02-22 20:35:49 +08:00
parent f0305685db
commit 0c5f7b2b84
2 changed files with 15 additions and 16 deletions

View File

@@ -9,7 +9,8 @@ import { useAriaProps, useSizeProp } from '@element-plus/hooks'
import { CHANGE_EVENT, UPDATE_MODEL_EVENT } from '@element-plus/constants'
import type { Option } from './types'
import type { ExtractPublicPropTypes } from 'vue'
import type { ComponentInstance, ExtractPublicPropTypes } from 'vue'
import type { ComponentExposed } from 'vue-component-type-helpers'
import type { ComponentSize } from '@element-plus/constants'
import type Segmented from './segmented.vue'
@@ -25,12 +26,12 @@ export const defaultProps: Required<Props> = {
disabled: 'disabled',
}
export interface SegmentedProps {
export interface SegmentedProps<T extends Option = Option> {
direction?: 'vertical' | 'horizontal'
/**
* @description options of segmented
*/
options?: Option[]
options?: T[]
/**
* @description binding value
*/
@@ -144,4 +145,5 @@ export const segmentedEmits = {
}
export type SegmentedEmits = typeof segmentedEmits
export type SegmentedInstance = InstanceType<typeof Segmented> & unknown
export type SegmentedInstance = ComponentInstance<typeof Segmented> &
ComponentExposed<typeof Segmented>

View File

@@ -24,14 +24,14 @@
@change="handleChange($event, item)"
/>
<div :class="ns.e('item-label')">
<slot :item="intoAny(item)">{{ getLabel(item) }}</slot>
<slot :item="item">{{ getLabel(item) }}</slot>
</div>
</label>
</div>
</div>
</template>
<script lang="ts" setup>
<script lang="ts" setup generic="T extends Option = Option">
import { computed, reactive, ref, watch } from 'vue'
import { useActiveElement, useResizeObserver } from '@vueuse/core'
import { useId, useNamespace } from '@element-plus/hooks'
@@ -52,7 +52,7 @@ defineOptions({
name: 'ElSegmented',
})
const props = withDefaults(defineProps<SegmentedProps>(), {
const props = withDefaults(defineProps<SegmentedProps<T>>(), {
direction: 'horizontal',
options: () => [],
props: () => defaultProps,
@@ -83,7 +83,7 @@ const state = reactive({
focusVisible: false,
})
const handleChange = (evt: Event, item: Option) => {
const handleChange = (evt: Event, item: T) => {
const value = getValue(item)
emit(UPDATE_MODEL_EVENT, value)
emit(CHANGE_EVENT, value)
@@ -92,25 +92,22 @@ const handleChange = (evt: Event, item: Option) => {
const aliasProps = computed(() => ({ ...defaultProps, ...props.props }))
//FIXME: remove this when vue >=3.3
const intoAny = (item: any) => item
const getValue = (item: Option) => {
const getValue = (item: T) => {
return isObject(item) ? item[aliasProps.value.value] : item
}
const getLabel = (item: Option) => {
const getLabel = (item: T) => {
return isObject(item) ? item[aliasProps.value.label] : item
}
const getDisabled = (item: Option | undefined) => {
const getDisabled = (item: T | undefined) => {
return !!(
_disabled.value ||
(isObject(item) ? item[aliasProps.value.disabled] : false)
)
}
const getSelected = (item: Option) => {
const getSelected = (item: T) => {
return props.modelValue === getValue(item)
}
@@ -118,7 +115,7 @@ const getOption = (value: any) => {
return props.options.find((item) => getValue(item) === value)
}
const getItemCls = (item: Option) => {
const getItemCls = (item: T) => {
return [
ns.e('item'),
ns.is('selected', getSelected(item)),