Skip to content

Commit

Permalink
fix(TextEllipsis): should recalculate the ellipsis state when activat…
Browse files Browse the repository at this point in the history
…ed (#12741)
  • Loading branch information
inottn committed Mar 31, 2024
1 parent 661f35d commit d87c5e2
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 24 deletions.
62 changes: 39 additions & 23 deletions packages/vant/src/text-ellipsis/TextEllipsis.tsx
Expand Up @@ -2,6 +2,7 @@ import {
ref,
watch,
computed,
onActivated,
onMounted,
defineComponent,
type ExtractPropTypes,
Expand Down Expand Up @@ -42,6 +43,7 @@ export default defineComponent({
const expanded = ref(false);
const hasAction = ref(false);
const root = ref<HTMLElement>();
let needRecalculate = false;

const actionText = computed(() =>
expanded.value ? props.collapseText : props.expandText,
Expand All @@ -53,29 +55,31 @@ export default defineComponent({
return match ? Number(match[0]) : 0;
};

const calcEllipsised = () => {
const cloneContainer = () => {
if (!root.value) return;

const originStyle = window.getComputedStyle(root.value);
const container = document.createElement('div');
const styleNames: string[] = Array.prototype.slice.apply(originStyle);
styleNames.forEach((name) => {
container.style.setProperty(name, originStyle.getPropertyValue(name));
});

container.style.position = 'fixed';
container.style.zIndex = '-9999';
container.style.top = '-9999px';
container.style.height = 'auto';
container.style.minHeight = 'auto';
container.style.maxHeight = 'auto';

container.innerText = props.content;
document.body.appendChild(container);
return container;
};
const cloneContainer = () => {
if (!root.value || !root.value.isConnected) return;

const originStyle = window.getComputedStyle(root.value);
const container = document.createElement('div');
const styleNames: string[] = Array.prototype.slice.apply(originStyle);

styleNames.forEach((name) => {
container.style.setProperty(name, originStyle.getPropertyValue(name));
});

container.style.position = 'fixed';
container.style.zIndex = '-9999';
container.style.top = '-9999px';
container.style.height = 'auto';
container.style.minHeight = 'auto';
container.style.maxHeight = 'auto';

container.innerText = props.content;
document.body.appendChild(container);

return container;
};

const calcEllipsised = () => {
const calcEllipsisText = (
container: HTMLDivElement,
maxHeight: number,
Expand Down Expand Up @@ -168,7 +172,12 @@ export default defineComponent({

// Calculate the interceptional text
const container = cloneContainer();
if (!container) return;

if (!container) {
needRecalculate = true;
return;
}

const { paddingBottom, paddingTop, lineHeight } = container.style;
const maxHeight = Math.ceil(
(Number(props.rows) + 0.5) * pxToNum(lineHeight) +
Expand Down Expand Up @@ -209,6 +218,13 @@ export default defineComponent({

onMounted(calcEllipsised);

onActivated(() => {
if (needRecalculate) {
needRecalculate = false;
calcEllipsised();
}
});

watch(
[windowWidth, () => [props.content, props.rows, props.position]],
calcEllipsised,
Expand Down
@@ -1,5 +1,5 @@
import { mount } from '../../../test';
import { nextTick } from 'vue';
import { defineComponent, KeepAlive, nextTick } from 'vue';
import TextEllipsis, { type TextEllipsisInstance } from '..';

const originGetComputedStyle = window.getComputedStyle;
Expand Down Expand Up @@ -34,6 +34,7 @@ afterAll(() => {

test('should render action slot correctly', async () => {
const wrapper = mount(TextEllipsis, {
attachTo: document.body,
props: {
content,
},
Expand All @@ -57,6 +58,7 @@ test('should render action slot correctly', async () => {

test('should render content correctly', async () => {
const wrapper = mount(TextEllipsis, {
attachTo: document.body,
props: {
content,
},
Expand All @@ -68,6 +70,7 @@ test('should render content correctly', async () => {

test('Expand and Collapse should be work', async () => {
const wrapper = mount(TextEllipsis, {
attachTo: document.body,
props: {
content,
expandText: 'expand',
Expand All @@ -83,6 +86,7 @@ test('Expand and Collapse should be work', async () => {

test('should emit click event after Expand/Collapse is clicked', async () => {
const wrapper = mount(TextEllipsis, {
attachTo: document.body,
props: {
content,
expandText: 'expand',
Expand All @@ -102,6 +106,7 @@ test('text not exceeded', async () => {

const shortContent = 'Vant is a component library';
const wrapper = mount(TextEllipsis, {
attachTo: document.body,
props: {
content: shortContent,
expandText: 'expand',
Expand All @@ -112,3 +117,45 @@ test('text not exceeded', async () => {
await nextTick();
expect(wrapper.text()).not.toMatch('...');
});

// https://github.com/vant-ui/vant/issues/12445
test('should recalculate the ellipsis state when the component is activated', async () => {
vi.useFakeTimers();

const Comp = defineComponent({
data() {
return {
show: false,
};
},
beforeMount() {
setTimeout(() => {
this.show = true;
}, 1000);
},
render() {
return this.show ? <TextEllipsis content={content} /> : null;
},
});

const wrapper = mount(
{
data() {
return {
render: true,
};
},
render() {
return <KeepAlive>{this.render ? <Comp /> : null}</KeepAlive>;
},
},
{ attachTo: document.body },
);

wrapper.setData({ render: false });
await vi.advanceTimersByTimeAsync(1000);
await wrapper.setData({ render: true });
expect(wrapper.text()).toMatch(content);

vi.useRealTimers();
});

0 comments on commit d87c5e2

Please sign in to comment.