This commit is contained in:
2026-08-07 18:44:55 +08:00
parent 2425e0cac1
commit 38a0ffd3e3
9 changed files with 272 additions and 40 deletions
@@ -0,0 +1,43 @@
import { defineComponent } from 'vue'
import { shallowMount } from '@vue/test-utils'
import { describe, expect, it } from 'vitest'
import LineClampText from './LineClampText.vue'
const TooltipStub = defineComponent({
props: { content: String, disabled: Boolean, visible: Boolean },
template: '<div class="tooltip-stub" :data-content="content" :data-visible="visible"><slot /></div>',
})
describe('LineClampText', () => {
it('defaults to one line and exposes the full text to hover and focus', async () => {
const wrapper = shallowMount(LineClampText, {
props: { content: '第一行\n第二行' },
global: { stubs: { ElTooltip: TooltipStub } },
})
const text = wrapper.get('.line-clamp-text')
expect(text.attributes('style')).toContain('--cc-line-clamp: 1')
expect(text.attributes('aria-label')).toBe('第一行\n第二行')
expect(wrapper.get('.tooltip-stub').attributes('data-content')).toBe('第一行\n第二行')
expect(wrapper.get('.tooltip-stub').attributes('data-visible')).toBe('false')
await text.trigger('mouseenter')
expect(wrapper.get('.tooltip-stub').attributes('data-visible')).toBe('true')
await text.trigger('mouseleave')
expect(wrapper.get('.tooltip-stub').attributes('data-visible')).toBe('false')
await text.trigger('focus')
expect(wrapper.get('.tooltip-stub').attributes('data-visible')).toBe('true')
await text.trigger('blur')
expect(wrapper.get('.tooltip-stub').attributes('data-visible')).toBe('false')
})
it('accepts two and three line limits', () => {
expect(shallowMount(LineClampText, {
props: { content: 'text', lines: 2 },
global: { stubs: { ElTooltip: TooltipStub } },
}).get('.line-clamp-text').attributes('style')).toContain('--cc-line-clamp: 2')
expect(shallowMount(LineClampText, {
props: { content: 'text', lines: 3 },
global: { stubs: { ElTooltip: TooltipStub } },
}).get('.line-clamp-text').attributes('style')).toContain('--cc-line-clamp: 3')
})
})
+48
View File
@@ -0,0 +1,48 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
const props = withDefaults(defineProps<{
content?: string | number | null
lines?: 1 | 2 | 3
}>(), {
content: '',
lines: 1,
})
const text = computed(() => props.content === null || props.content === undefined ? '' : String(props.content))
const lineStyle = computed(() => ({ '--cc-line-clamp': props.lines }))
const tooltipVisible = ref(false)
function showTooltip() {
if (text.value) tooltipVisible.value = true
}
function hideTooltip() {
tooltipVisible.value = false
}
</script>
<template>
<el-tooltip
:content="text || '—'"
:disabled="!text"
:visible="Boolean(text) && tooltipVisible"
placement="top-start"
>
<span
class="line-clamp-text"
:style="lineStyle"
:tabindex="text ? 0 : undefined"
:aria-label="text || '—'"
@mouseenter="showTooltip"
@mouseleave="hideTooltip"
@focus="showTooltip"
@blur="hideTooltip"
>{{ text || '—' }}</span>
</el-tooltip>
</template>
<style scoped>
.line-clamp-text { display: -webkit-box; min-width: 0; overflow: hidden; line-height: 1.5; -webkit-box-orient: vertical; -webkit-line-clamp: var(--cc-line-clamp); overflow-wrap: anywhere; white-space: pre-line; }
.line-clamp-text:focus-visible { outline: 2px solid color-mix(in srgb, var(--cc-primary) 45%, transparent); outline-offset: 2px; }
</style>