1
0
mirror of https://gitee.com/vant-contrib/vant.git synced 2025-04-06 03:57:59 +08:00

feat(TextEllipsis): add position prop ()

* feat(TextEllipsis): add position prop

* docs: update docs

* chore: optimize code
This commit is contained in:
Gavin 2023-07-08 17:03:37 +08:00 committed by GitHub
parent 0c47654da5
commit 3b9c72d09e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 268 additions and 36 deletions

@ -81,17 +81,64 @@ export default {
};
```
### Custom Collapse Position
- Collapse the beginning part of the content:
```html
<van-text-ellipsis
rows="1"
:content="text"
expand-text="expand"
collapse-text="collapse"
position="start"
/>
```
```js
export default {
setup() {
const text =
"That day, I turned twenty-one. In the golden age of my life, I was full of dreams. I wanted to love, to eat, and to instantly transform into one of these clouds, part alight, part darkened. It was only later that I understood life is but a slow, drawn-out process of getting your balls crushed. Day by day, you get older. Day by day, your dreams fade. In the end you are no different from a crushed ox. But I hadn't foreseen any of it on my twenty-first birthday. I thought I would be vigorous forever, and that nothing could ever crush me.";
return { text };
},
};
```
- Collapse the middle part of the content:
```html
<van-text-ellipsis
rows="2"
:content="text"
expand-text="expand"
collapse-text="collapse"
position="middle"
/>
```
```js
export default {
setup() {
const text =
"That day, I turned twenty-one. In the golden age of my life, I was full of dreams. I wanted to love, to eat, and to instantly transform into one of these clouds, part alight, part darkened. It was only later that I understood life is but a slow, drawn-out process of getting your balls crushed. Day by day, you get older. Day by day, your dreams fade. In the end you are no different from a crushed ox. But I hadn't foreseen any of it on my twenty-first birthday. I thought I would be vigorous forever, and that nothing could ever crush me.";
return { text };
},
};
```
## API
### Props
| Attribute | Description | Type | Default |
| ------------- | ------------------------ | ------------------ | ------- |
| rows | Number of rows displayed | _number \| string_ | `1` |
| content | The text displayed | _string_ | - |
| expand-text | Expand operation text | _string_ | - |
| collapse-text | Collapse operation text | _string_ | - |
| dots `v4.2.0` | Text content of ellipsis | _string_ | `'...'` |
| Attribute | Description | Type | Default |
| --- | --- | --- | --- |
| rows | Number of rows displayed | _number \| string_ | `1` |
| content | The text displayed | _string_ | - |
| expand-text | Expand operation text | _string_ | - |
| collapse-text | Collapse operation text | _string_ | - |
| dots `v4.2.0` | Text content of ellipsis | _string_ | `'...'` |
| position `v4.6.2` | Can be set to `start` `middle` | _string_ | `'end'` |
### Events

@ -76,17 +76,66 @@ export default {
};
```
### 自定义省略位置
通过设置 `position` 控制省略位置。
- 头部省略:
```html
<van-text-ellipsis
rows="1"
:content="text"
expand-text="展开"
collapse-text="收起"
position="start"
/>
```
```js
export default {
setup() {
const text =
'那一天我二十一岁,在我一生的黄金时代。我有好多奢望。我想爱,想吃,还想在一瞬间变成天上半明半暗的云。后来我才知道,生活就是个缓慢受锤的过程,人一天天老下去,奢望也一天天消失,最后变得像挨了锤的牛一样。可是我过二十一岁生日时没有预见到这一点。我觉得自己会永远生猛下去,什么也锤不了我。';
return { text };
},
};
```
- 中部省略:
```html
<van-text-ellipsis
rows="2"
:content="text"
expand-text="展开"
collapse-text="收起"
position="middle"
/>
```
```js
export default {
setup() {
const text =
'那一天我二十一岁,在我一生的黄金时代。我有好多奢望。我想爱,想吃,还想在一瞬间变成天上半明半暗的云。后来我才知道,生活就是个缓慢受锤的过程,人一天天老下去,奢望也一天天消失,最后变得像挨了锤的牛一样。可是我过二十一岁生日时没有预见到这一点。我觉得自己会永远生猛下去,什么也锤不了我。';
return { text };
},
};
```
## API
### Props
| 参数 | 说明 | 类型 | 默认值 |
| ------------- | ---------------- | ------------------ | ------- |
| rows | 展示的行数 | _number \| string_ | `1` |
| content | 需要展示的文本 | _string_ | - |
| expand-text | 展开操作的文案 | _string_ | - |
| collapse-text | 收起操作的文案 | _string_ | - |
| dots `v4.2.0` | 省略号的文本内容 | _string_ | `'...'` |
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| rows | 展示的行数 | _number \| string_ | `1` |
| content | 需要展示的文本 | _string_ | - |
| expand-text | 展开操作的文案 | _string_ | - |
| collapse-text | 收起操作的文案 | _string_ | - |
| dots `v4.2.0` | 省略号的文本内容 | _string_ | `'...'` |
| position `v4.6.2` | 省略位置,可选值为 `start` `middle` | _string_ | `'end'` |
### Events

@ -1,6 +1,7 @@
import {
ref,
watch,
computed,
onMounted,
defineComponent,
type ExtractPropTypes,
@ -20,6 +21,7 @@ export const textEllipsisProps = {
content: makeStringProp(''),
expandText: makeStringProp(''),
collapseText: makeStringProp(''),
position: makeStringProp('end'),
};
export type TextEllipsisProps = ExtractPropTypes<typeof textEllipsisProps>;
@ -37,6 +39,10 @@ export default defineComponent({
const hasAction = ref(false);
const root = ref<HTMLElement>();
const actionText = computed(() =>
expanded.value ? props.expandText : props.collapseText
);
const pxToNum = (value: string | null) => {
if (!value) return 0;
const match = value.match(/^\d*(\.\d*)?/);
@ -70,33 +76,104 @@ export default defineComponent({
container: HTMLDivElement,
maxHeight: number
) => {
const { dots, content, expandText } = props;
const { content, position, dots } = props;
const end = content.length;
let left = 0;
let right = content.length;
let res = -1;
const calcEllipse = () => {
// calculate the former or later content
const tail = (left: number, right: number): string => {
if (right - left <= 1) {
if (position === 'end') {
return content.slice(0, left) + dots;
}
return dots + content.slice(right, end);
}
while (left <= right) {
const mid = Math.floor((left + right) / 2);
container.innerText = content.slice(0, mid) + dots + expandText;
if (container.offsetHeight <= maxHeight) {
left = mid + 1;
res = mid;
} else {
right = mid - 1;
const middle = Math.round((left + right) >> 1);
// Set the interception location
if (position === 'end') {
container.innerText =
content.slice(0, middle) + dots + actionText.value;
} else {
container.innerText =
dots + content.slice(middle, end) + actionText.value;
}
// The height after interception still does not match the rquired height
if (container.offsetHeight > maxHeight) {
if (position === 'end') {
return tail(left, middle);
}
return tail(middle, right);
}
if (position === 'end') {
return tail(middle, right);
}
return tail(left, middle);
};
container.innerText = tail(0, end);
};
const middleTail = (
leftPart: [number, number],
rightPart: [number, number]
): string => {
if (
leftPart[1] - leftPart[0] <= 1 &&
rightPart[1] - rightPart[0] <= 1
) {
return (
content.slice(0, leftPart[1]) +
dots +
dots +
content.slice(rightPart[1], end)
);
}
}
return content.slice(0, res) + dots;
const leftMiddle = Math.floor((leftPart[0] + leftPart[1]) >> 1);
const rightMiddle = Math.ceil((rightPart[0] + rightPart[1]) >> 1);
container.innerText =
props.content.slice(0, leftMiddle) +
props.dots +
actionText.value +
props.dots +
props.content.slice(rightMiddle, end);
if (container.offsetHeight >= maxHeight) {
return middleTail(
[leftPart[0], leftMiddle],
[rightMiddle, rightPart[1]]
);
}
return middleTail(
[leftMiddle, leftPart[1]],
[rightPart[0], rightMiddle]
);
};
const middle = (0 + end) >> 1;
props.position === 'middle'
? (container.innerText = middleTail([0, middle], [middle, end]))
: calcEllipse();
return container.innerText;
};
// Calculate the interceptional text
const container = cloneContainer();
if (!container) return;
const { paddingBottom, paddingTop, lineHeight } = container.style;
const maxHeight =
const maxHeight = Math.ceil(
(Number(props.rows) + 0.5) * pxToNum(lineHeight) +
pxToNum(paddingTop) +
pxToNum(paddingBottom);
pxToNum(paddingTop) +
pxToNum(paddingBottom)
);
if (maxHeight < container.offsetHeight) {
hasAction.value = true;
text.value = calcEllipsisText(container, maxHeight);
@ -121,7 +198,7 @@ export default defineComponent({
onMounted(calcEllipsised);
watch(() => [props.content, props.rows], calcEllipsised);
watch(() => [props.content, props.rows, props.position], calcEllipsised);
useEventListener('resize', calcEllipsised);

@ -13,6 +13,9 @@ const t = useTranslate({
collapseText: '收起',
expandCollapse: '展开/收起',
customRows: '自定义展示行数',
collapsePosition: '自定义省略位置',
collapseStart: '头部省略',
collapseMiddle: '中部省略',
},
'en-US': {
text1:
@ -25,6 +28,9 @@ const t = useTranslate({
collapseText: 'collapse',
expandCollapse: 'Expand/Collapse',
customRows: 'Customize Rows',
collapsePosition: 'Custom Collapse Position',
collapseStart: 'Head Area Collapse Position',
collapseMiddle: 'Middle Area Collapse Position',
},
});
</script>
@ -50,6 +56,28 @@ const t = useTranslate({
:collapse-text="t('collapseText')"
/>
</demo-block>
<demo-block :title="t('collapsePosition')">
<demo-block :title="t('collapseStart')">
<van-text-ellipsis
rows="1"
:content="t('text3')"
:expand-text="t('expandText')"
:collapse-text="t('collapseText')"
position="start"
/>
</demo-block>
<demo-block :title="t('collapseMiddle')">
<van-text-ellipsis
rows="2"
:content="t('text3')"
:expand-text="t('expandText')"
:collapse-text="t('collapseText')"
position="middle"
/>
</demo-block>
</demo-block>
</template>
<style lang="less">

@ -17,4 +17,17 @@ exports[`should render demo and match snapshot 1`] = `
<div class="van-text-ellipsis">
</div>
</div>
<div>
<!--[-->
<div>
<!--[-->
<div class="van-text-ellipsis">
</div>
</div>
<div>
<!--[-->
<div class="van-text-ellipsis">
</div>
</div>
</div>
`;

@ -3,14 +3,14 @@
exports[`should render demo and match snapshot 1`] = `
<div>
<div class="van-text-ellipsis">
Take your time and be patient. Life itself will eventually answer all those questions it once raised for you...
...
<span class="van-text-ellipsis__action">
</span>
</div>
</div>
<div>
<div class="van-text-ellipsis">
The fleeting time of one's life is everything that belongs to a person. Only this thing truly belongs to you. Everything else is just a momentary pleasure or misfortune, which will soon be gone with the passing of time...
...
<span class="van-text-ellipsis__action">
expand
</span>
@ -18,10 +18,28 @@ exports[`should render demo and match snapshot 1`] = `
</div>
<div>
<div class="van-text-ellipsis">
That day, I turned twenty-one. In the golden age of my life, I was full of dreams. I wanted to love, to eat, and to instantly transform into one of these clouds, part alight, part darkened. It was only later that I understood life is but a slow, drawn-out process of getting your balls crushed. Day by day, you get older. Day by day, your dreams fade. In the end you are no different from a crushed ox. But I hadn't foreseen any of it on my twenty-first birthday. I thought I would be vigorous forever, and that nothing could ever crush me...
...
<span class="van-text-ellipsis__action">
expand
</span>
</div>
</div>
<div>
<div>
<div class="van-text-ellipsis">
...
<span class="van-text-ellipsis__action">
expand
</span>
</div>
</div>
<div>
<div class="van-text-ellipsis">
......
<span class="van-text-ellipsis__action">
expand
</span>
</div>
</div>
</div>
`;