mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2026-09-13 07:28:37 +00:00
fix(form): 避免 Tooltip 无合法触发器时报 ElOnlyChild
对比模式删除按钮与表格未就绪时,ElTooltip 默认插槽会变成 Comment,触发 Element Plus 警告。
This commit is contained in:
parent
a7999f50d5
commit
90e4bec70b
@ -1,5 +1,11 @@
|
||||
<template>
|
||||
<component class="tmagic-design-tooltip" :is="uiComponent" v-bind="uiProps">
|
||||
<!-- ElTooltip 的 ElOnlyChild 要求默认插槽至少有一个真实节点;v-if 为 false 时插槽是 Comment,会报 no valid child node found。 -->
|
||||
<component
|
||||
v-if="isLegitTooltipTrigger($slots.default?.())"
|
||||
class="tmagic-design-tooltip"
|
||||
:is="uiComponent"
|
||||
v-bind="uiProps"
|
||||
>
|
||||
<template #content>
|
||||
<slot name="content"></slot>
|
||||
</template>
|
||||
@ -8,7 +14,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { Comment, computed, Fragment, Text, type VNode } from 'vue';
|
||||
|
||||
import { getDesignConfig } from './config';
|
||||
import type { TooltipProps } from './types';
|
||||
@ -24,4 +30,30 @@ const ui = getDesignConfig('components')?.tooltip;
|
||||
const uiComponent = ui?.component || 'el-tooltip';
|
||||
|
||||
const uiProps = computed<TooltipProps>(() => ui?.props(props) || props);
|
||||
|
||||
/** 与 Element Plus `findFirstLegitChild` 对齐:Comment / 空文本不算合法 trigger。 */
|
||||
const isLegitTooltipTrigger = (nodes: VNode[] | undefined): boolean => {
|
||||
if (!nodes?.length) return false;
|
||||
|
||||
for (const child of nodes) {
|
||||
if (!child) continue;
|
||||
|
||||
switch (child.type) {
|
||||
case Comment:
|
||||
continue;
|
||||
case Text: {
|
||||
const text = typeof child.children === 'string' ? child.children.trim() : '';
|
||||
if (text) return true;
|
||||
continue;
|
||||
}
|
||||
case Fragment:
|
||||
if (isLegitTooltipTrigger(child.children as VNode[])) return true;
|
||||
continue;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
</script>
|
||||
|
||||
@ -80,9 +80,9 @@
|
||||
</div>
|
||||
</TMagicPopover>
|
||||
|
||||
<TMagicTooltip :content="`删除 ${title}`">
|
||||
<!-- v-if 必须挂在 Tooltip 上:子节点为 false 时 ElOnlyChild 会报 no valid child node found -->
|
||||
<TMagicTooltip v-if="!isCompare" :content="`删除 ${title}`">
|
||||
<TMagicButton
|
||||
v-if="!isCompare"
|
||||
v-show="showDelete"
|
||||
size="default"
|
||||
link
|
||||
|
||||
@ -8,13 +8,14 @@
|
||||
>
|
||||
<div class="m-fields-table" :class="{ 'm-fields-table-item-extra': config.itemExtra }">
|
||||
<span v-if="config.extra" style="color: rgba(0, 0, 0, 0.45)" v-html="config.extra"></span>
|
||||
<!-- v-if 必须挂在 Tooltip 上:表格未就绪时 ElOnlyChild 会报 no valid child node found -->
|
||||
<TMagicTooltip
|
||||
v-if="model[modelName]"
|
||||
content="拖拽可排序"
|
||||
placement="left-start"
|
||||
:disabled="config.dropSort !== true || config.dropSortHandle"
|
||||
>
|
||||
<TMagicTable
|
||||
v-if="model[modelName]"
|
||||
ref="tMagicTable"
|
||||
style="width: 100%"
|
||||
show-header
|
||||
|
||||
@ -180,7 +180,8 @@ describe('GroupList container', () => {
|
||||
expect(item.props('model')).toEqual({});
|
||||
});
|
||||
|
||||
test('对比模式隐藏底部操作栏与复制/移动按钮', async () => {
|
||||
test('对比模式隐藏底部操作栏与复制/移动/删除按钮,且不触发 ElOnlyChild 警告', async () => {
|
||||
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
||||
const wrapper = mountForm(
|
||||
compareConfig,
|
||||
{ list: [{ text: 'a' }, { text: 'b' }] },
|
||||
@ -192,9 +193,14 @@ describe('GroupList container', () => {
|
||||
await nextTick();
|
||||
await nextTick();
|
||||
expect(wrapper.find('.m-fields-group-list-footer').exists()).toBe(false);
|
||||
expect(wrapper.find('.delete-button').exists()).toBe(false);
|
||||
expect(wrapper.text()).not.toContain('复制');
|
||||
expect(wrapper.text()).not.toContain('上移');
|
||||
expect(wrapper.text()).not.toContain('下移');
|
||||
expect(
|
||||
warn.mock.calls.some((args) => args.some((arg) => String(arg?.message ?? arg).includes('ElOnlyChild'))),
|
||||
).toBe(false);
|
||||
warn.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 2025 Tencent.
|
||||
*/
|
||||
import { describe, expect, test } from 'vitest';
|
||||
import { describe, expect, test, vi } from 'vitest';
|
||||
import { nextTick } from 'vue';
|
||||
import { mount } from '@vue/test-utils';
|
||||
import ElementPlus from 'element-plus';
|
||||
@ -41,4 +41,14 @@ describe('Table container —— 对比模式', () => {
|
||||
await nextTick();
|
||||
expect(wrapper.text()).not.toContain('清空');
|
||||
});
|
||||
|
||||
test('model 为空时不渲染表格,且不触发 ElOnlyChild 警告', async () => {
|
||||
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
||||
mountTable({ model: { list: undefined } });
|
||||
await nextTick();
|
||||
expect(
|
||||
warn.mock.calls.some((args) => args.some((arg) => String(arg?.message ?? arg).includes('ElOnlyChild'))),
|
||||
).toBe(false);
|
||||
warn.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user