mirror of
https://github.com/element-plus/element-plus.git
synced 2026-03-13 07:51:17 +08:00
Merge branch 'feat/cascader-first-level-display' of https://github.com/WANGXIAOYU1995/element-plus into feat/cascader-first-level-display
This commit is contained in:
@@ -382,6 +382,8 @@ describe('Select', () => {
|
||||
})
|
||||
|
||||
test('the scenario of rendering label when there is a default value and persistent is false', 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="value" :persistent="false">
|
||||
@@ -410,9 +412,12 @@ describe('Select', () => {
|
||||
await nextTick()
|
||||
|
||||
expect(wrapper.find(`.${PLACEHOLDER_CLASS_NAME}`).text()).toBe('双皮奶')
|
||||
delete process.env.RUN_TEST_WITH_PERSISTENT
|
||||
})
|
||||
|
||||
test('when there is a default value and persistent is false, render the label and dynamically modify options', 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="value" :persistent="false">
|
||||
@@ -444,9 +449,12 @@ describe('Select', () => {
|
||||
await nextTick()
|
||||
|
||||
expect(wrapper.find(`.${PLACEHOLDER_CLASS_NAME}`).text()).toBe('双皮奶')
|
||||
delete process.env.RUN_TEST_WITH_PERSISTENT
|
||||
})
|
||||
|
||||
test('multiple is true and persistent is false', 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="value" :persistent="false" multiple>
|
||||
@@ -477,6 +485,7 @@ describe('Select', () => {
|
||||
const tags = wrapper.findAll(`.${TAG_NAME}`)
|
||||
expect(tags.length).toBe(1)
|
||||
expect(tags[0].text()).toBe('双皮奶')
|
||||
delete process.env.RUN_TEST_WITH_PERSISTENT
|
||||
})
|
||||
|
||||
test('multiple is true and persistent is false, render the label and dynamically modify options', async () => {
|
||||
@@ -1382,7 +1391,7 @@ 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
|
||||
process.env.RUN_TEST_WITH_PERSISTENT = 'true'
|
||||
|
||||
wrapper = _mount(
|
||||
`
|
||||
|
||||
@@ -300,7 +300,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Fragment, computed, defineComponent, h, nextTick, provide, reactive, toRefs, watchEffect } from 'vue'
|
||||
import { computed, defineComponent, getCurrentInstance, provide, reactive, toRefs, watch } 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, VNodeNormalizedChildren } from 'vue';
|
||||
import type { VNode } from 'vue';
|
||||
import type { SelectContext } from './type'
|
||||
|
||||
const COMPONENT_NAME = 'ElSelect'
|
||||
@@ -346,6 +346,16 @@ export default defineComponent({
|
||||
],
|
||||
|
||||
setup(props, { emit, slots }) {
|
||||
const instance = getCurrentInstance()!
|
||||
instance.appContext.config.warnHandler = (...args) => {
|
||||
// Overrides warnings about slots not being executable outside of a render function.
|
||||
// We call slot below just to simulate data when persist is false, this warning message should be ignored
|
||||
if (!args[0] || args[0].includes('Slot "default" invoked outside of the render function')) {
|
||||
return
|
||||
}
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(...args)
|
||||
}
|
||||
const modelValue = computed(() => {
|
||||
const { modelValue: rawModelValue, multiple } = props
|
||||
const fallback = multiple ? [] : undefined
|
||||
@@ -366,27 +376,54 @@ export default defineComponent({
|
||||
const API = useSelect(_props, emit)
|
||||
const { calculatorRef, inputStyle } = useCalcInputWidth()
|
||||
|
||||
const manuallyRenderSlots = (vnodes: VNodeNormalizedChildren) => {
|
||||
const flatTreeSelectData = (data: any[]) => {
|
||||
return data.reduce((acc, item) => {
|
||||
acc.push(item)
|
||||
if (item.children && item.children.length > 0) {
|
||||
acc.push(...flatTreeSelectData(item.children))
|
||||
}
|
||||
return acc
|
||||
}, [])
|
||||
}
|
||||
|
||||
const manuallyRenderSlots = (vnodes: VNode[] | undefined) => {
|
||||
// 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.
|
||||
const children = flattedChildren(vnodes) as VNode[]
|
||||
children.filter((item) => {
|
||||
const children = flattedChildren(vnodes || []) as VNode[]
|
||||
children.forEach((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)
|
||||
if (isObject(item) && (item.type.name === 'ElOption' || item.type.name === 'ElTree')) {
|
||||
// @ts-expect-error
|
||||
const _name = item.type.name
|
||||
if (_name === 'ElTree') {
|
||||
// tree-select component is a special case.
|
||||
// So we need to handle it separately.
|
||||
const treeData = item.props?.data || []
|
||||
const flatData = flatTreeSelectData(treeData)
|
||||
flatData.forEach((treeItem: any) => {
|
||||
treeItem.currentLabel = treeItem.label || (isObject(treeItem.value) ? '' : treeItem.value)
|
||||
API.onOptionCreate(treeItem)
|
||||
})
|
||||
} else if (_name === 'ElOption') {
|
||||
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 slotsContent = slots.default?.()
|
||||
return slotsContent
|
||||
}, newSlot => {
|
||||
if (props.persistent) {
|
||||
// If persistent is true, we don't need to manually render slots.
|
||||
return
|
||||
}
|
||||
manuallyRenderSlots(newSlot)
|
||||
}, {
|
||||
immediate: true,
|
||||
})
|
||||
|
||||
provide(
|
||||
|
||||
@@ -99,6 +99,24 @@ describe('TreeSelect.vue', () => {
|
||||
expect(tree.findAll('.el-tree .el-tree-node').length).toBe(1)
|
||||
})
|
||||
|
||||
test('render tree-select with default value and persistent is false', async () => {
|
||||
// This is convenient for testing the default value label rendering when persistent is false.
|
||||
process.env.RUN_TEST_WITH_PERSISTENT = 'true'
|
||||
const { select, wrapper } = createComponent({
|
||||
props: {
|
||||
persistent: false,
|
||||
modelValue: 1,
|
||||
},
|
||||
})
|
||||
|
||||
await nextTick()
|
||||
|
||||
expect(select.vm.modelValue).toBe(1)
|
||||
expect(select.vm.states.selectedLabel).toBe('一级 1')
|
||||
expect(wrapper.find('.el-select__placeholder').text()).toBe('一级 1')
|
||||
delete process.env.RUN_TEST_WITH_PERSISTENT
|
||||
})
|
||||
|
||||
test('render tree-select with dynamic class', async () => {
|
||||
const isClass = ref(false)
|
||||
const { wrapper } = createComponent({
|
||||
|
||||
@@ -5,7 +5,7 @@ export default {
|
||||
label: 'Хлебные крошки',
|
||||
},
|
||||
colorpicker: {
|
||||
confirm: 'подтверждать',
|
||||
confirm: 'Ок',
|
||||
clear: 'Очистить',
|
||||
},
|
||||
datepicker: {
|
||||
@@ -13,7 +13,7 @@ export default {
|
||||
today: 'Сегодня',
|
||||
cancel: 'Отмена',
|
||||
clear: 'Очистить',
|
||||
confirm: 'подтверждать',
|
||||
confirm: 'Ок',
|
||||
selectDate: 'Выбрать дату',
|
||||
selectTime: 'Выбрать время',
|
||||
startDate: 'Дата начала',
|
||||
@@ -91,7 +91,7 @@ export default {
|
||||
},
|
||||
messagebox: {
|
||||
title: 'Сообщение',
|
||||
confirm: 'подтверждать',
|
||||
confirm: 'Ок',
|
||||
cancel: 'Отмена',
|
||||
error: 'Недопустимый ввод данных',
|
||||
},
|
||||
@@ -103,7 +103,7 @@ export default {
|
||||
},
|
||||
table: {
|
||||
emptyText: 'Нет данных',
|
||||
confirmFilter: 'Подтвердить',
|
||||
confirmFilter: 'Ок',
|
||||
resetFilter: 'Сбросить',
|
||||
clearFilter: 'Все',
|
||||
sumText: 'Сумма',
|
||||
@@ -131,7 +131,7 @@ export default {
|
||||
title: 'Назад',
|
||||
},
|
||||
popconfirm: {
|
||||
confirmButtonText: 'подтверждать',
|
||||
confirmButtonText: 'Ок',
|
||||
cancelButtonText: 'Отмена',
|
||||
},
|
||||
carousel: {
|
||||
|
||||
2
typings/env.d.ts
vendored
2
typings/env.d.ts
vendored
@@ -5,7 +5,7 @@ declare global {
|
||||
const process: {
|
||||
env: {
|
||||
NODE_ENV: string
|
||||
RUN_TEST_WITH_PERSISTENT: boolean
|
||||
RUN_TEST_WITH_PERSISTENT: string
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user