refactor(components): [select] modify manuallyRenderSlots execute (#20854)

* refactor(components): [select] modify `manuallyRenderSlots` execute

* refactor(components): [select] modify ’manuallyRenderSlots‘ execute

* fix(components): [select] fix render slots attempt when persistent=false

* fix: remove duplicate judgments

---------

Co-authored-by: Dsaquel <291874700n@gmail.com>
Co-authored-by: btea <2356281422@qq.com>
This commit is contained in:
Jeff
2025-06-06 08:56:35 +08:00
committed by GitHub
parent 8098ddc180
commit 6f8e91f771
3 changed files with 25 additions and 27 deletions

View File

@ -1,7 +1,7 @@
// @ts-nocheck
import { defineComponent, markRaw, nextTick, ref } from 'vue'
import { mount } from '@vue/test-utils'
import { afterEach, beforeEach, describe, expect, it, test, vi } from 'vitest'
import { afterEach, describe, expect, it, test, vi } from 'vitest'
import { EVENT_CODE } from '@element-plus/constants'
import { ArrowDown, CaretTop, CircleClose } from '@element-plus/icons-vue'
import { usePopperContainerId } from '@element-plus/hooks'
@ -311,13 +311,8 @@ const TAG_NAME = `${WRAPPER_CLASS_NAME} .el-tag`
describe('Select', () => {
let wrapper: ReturnType<typeof _mount>
beforeEach(() => {
// This is convenient for testing the default value label rendering when persistent is false.
process.env.RUN_TEST_WITH_PERSISTENT = true
})
afterEach(() => {
document.body.innerHTML = ''
delete process.env.RUN_TEST_WITH_PERSISTENT
})
test('create', async () => {
@ -1386,6 +1381,9 @@ describe('Select', () => {
})
test('multiple select with collapseTagsTooltip', async () => {
// This is convenient for testing the default value label rendering when persistent is false.
process.env.RUN_TEST_WITH_PERSISTENT = true
wrapper = _mount(
`
<el-select v-model="selectedList" multiple collapseTags collapse-tags-tooltip placeholder="请选择">
@ -1433,6 +1431,8 @@ describe('Select', () => {
const tags = document.querySelectorAll('.el-select__tags-text')
expect(tags.length).toBe(2)
expect(tags[1].textContent).toBe(' + 2')
delete process.env.RUN_TEST_WITH_PERSISTENT
})
test('multiple select with maxCollapseTags', async () => {

View File

@ -300,7 +300,7 @@
</template>
<script lang="ts">
import { computed, defineComponent, provide, reactive, toRefs, watch } from 'vue'
import { Fragment, computed, defineComponent, h, nextTick, provide, reactive, toRefs, watchEffect } from 'vue'
import { ClickOutside } from '@element-plus/directives'
import ElTooltip from '@element-plus/components/tooltip'
import ElScrollbar from '@element-plus/components/scrollbar'
@ -316,7 +316,7 @@ import { selectKey } from './token'
import ElOptions from './options'
import { selectProps } from './select'
import type { VNode } from 'vue';
import type { VNode, VNodeNormalizedChildren } from 'vue';
import type { SelectContext } from './type'
const COMPONENT_NAME = 'ElSelect'
@ -366,29 +366,27 @@ export default defineComponent({
const API = useSelect(_props, emit)
const { calculatorRef, inputStyle } = useCalcInputWidth()
const manuallyRenderSlots = (defaultSlots: VNode[] | undefined) => {
const manuallyRenderSlots = (vnodes: VNodeNormalizedChildren) => {
// After option rendering is completed, the useSelect internal state can collect the value of each option.
// If the persistent value is false, option will not be rendered by default, so in this case,
// manually render and load option data here.
if (!props.persistent && defaultSlots) {
const children = flattedChildren(defaultSlots) as VNode[]
children.filter((item) => {
// @ts-expect-error
return isObject(item) && item!.type.name === 'ElOption'
}).forEach(item => {
const obj = { ...item.props } as any
obj.currentLabel = obj.label || (isObject(obj.value) ? '' : obj.value)
API.onOptionCreate(obj)
const children = flattedChildren(vnodes) as VNode[]
children.filter((item) => {
// @ts-expect-error
return isObject(item) && item!.type.name === 'ElOption'
}).forEach(item => {
const obj = { ...item.props } as any
obj.currentLabel = obj.label || (isObject(obj.value) ? '' : obj.value)
API.onOptionCreate(obj)
})
}
watchEffect(() => {
if (!props.persistent) {
nextTick(() => {
const defaultSlots = h(Fragment, slots.default?.() ?? []).children
manuallyRenderSlots(defaultSlots)
})
}
}
watch(() => {
const currentSlot = slots.default?.()
return currentSlot
}, (newSlot) => {
manuallyRenderSlots(newSlot)
}, {
immediate: true,
})
provide(

View File

@ -33,7 +33,7 @@ export const useTree = (
}
) => {
watch(
() => props.modelValue,
[() => props.modelValue, tree],
() => {
if (props.showCheckbox) {
nextTick(() => {