Requirement generation: In a recent project, the product wanted us to automatically overflow and hide ellipsis display of text beyond n lines (according to the requirements of the project, it was hoped that text beyond 1/2/3/4 lines could be processed) in the table display, and mouse over the display tooltip. Normal text content is displayed properly. Here’s the problem. Reading the documentation for Element tables, IT turns out that there is something about content overflow that hides the tooltip display, but it has some drawbacks, such as:
- Only overflow hiding beyond one line is supported
- When the mouse moves into the tooltip, the bubble disappears, preventing the user from copying the tooltip
- Unable to control display hidden time, etc
Therefore, for the above reasons, we need to customize our own methods to implement this function.
Ps: This is mainly about the idea, so I will directly use the table wrapped in my project (projects usually wrap tables and work with common styles and methods of tables), and the project is based on Vue3+typescript, but it is the same for vue2 and so on. For vue2, you just need to modify the syntax of the following components to use it directly
Here I first share the implementation principle and ideas (the principle is to use JS and CSS cooperation to achieve), the process will talk about the shortcomings of the current way, may be improved in the future, but it has already met the needs of the project. Component complete code below!
1. Determine whether the content needs to be hidden by overflow
The first and most important thing is to determine whether the content needs to be spilled or hidden. The logic involved is as follows:
/ * * *@description: Gets the actual width, up to a few characters per line and up to a few lines *@param {*}
* @return {*}* /
const getOverFlowData = (width: string) = > {
// Table cell has a total of 20 inner margins and 1px to subtract
const realWidth = parseInt(width) - 21
// The maximum number of characters in a line is 6 px.
const rowChar = Math.floor(realWidth / 6)
// Get at most a few lines to display (this is passed by the parent component)
const row = props.overflowRow
return {
rowChar,
row
}
}
/ * * *@description: Indicates whether tooltip * is displayed@param {*}
* @return {*}* /
const computeOverflow = (val: string, width: string): boolean= > {
if (typeofval ! = ='string'| |! width)return false
// The content character length
let len = 0
for (let i = 0; i < val.length; i++) {
const code = val.charCodeAt(i)
len++
// Two characters in Chinese
if (code > 255) {
len++
}
}
Call the getOverFlowData method above
const { rowChar, row } = getOverFlowData(width)
// console.log(len, rowChar, row * rowChar)
return row * rowChar < len
}
Copy the code
Font size is 12px, the width of a Chinese character is about 12px. Since one Chinese character is two characters long, the width of a Chinese character is about 12px. So a character is 6px wide.
You’ll also notice that both methods require width, which is the fixed width we set for el-table-column. Yes, that’s one of the minor drawbacks of this feature, you have to give the el-table-column a fixed width, not min-width or anything else, because we need to actually get its width. Currently, other methods to obtain the width will encounter many problems (such as dom acquisition, and then need to consider the resize event, that is to say, the screen width is changed every time to obtain the content width, feeling very expensive performance), to see if we can optimize in the future. But you can’t set all the columns of the table to a fixed width, at least one of them has to stretch itself, or you might end up with a problem where all the widths don’t add up to fill the screen
2. Add CSS class control ellipsis to the text to determine the need for overflow hiding
Set overflow hiding by setting the style. The class name format is tooltip-text-x, and you can dynamically set the class name in template. The code involved is as follows:
CSS core code
.tooltip-text-1..tooltip-text-2..tooltip-text-3..tooltip-text-4 {
display: inline-block;
display: -webkit-box;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
}
.tooltip-text-1 {
-webkit-line-clamp: 1;
}
.tooltip-text-2 {
-webkit-line-clamp: 2;
}
.tooltip-text-3 {
-webkit-line-clamp: 3;
}
.tooltip-text-4 {
-webkit-line-clamp: 4;
}
Copy the code
OverflowRow overflowRow overflowRow overflowRow overflowRow overflowRow overflowRow
<span :class="[`tooltip-text-${overflowRow}`]">{{ value }}</span>
Copy the code
If you want to hide more than 5 lines, you need to manually write more. That is to say, the CSS supports only 1/2/3/4 lines. There are compatibility problems, but the project has already used VUE3, so the problem is not big. It is also worth noting that even if a line is overflow hidden, do not use overflow: hidden; text-overflow: ellipsis; white-space: nowrap; This will cause the tooltip to appear in the wrong position, which can be found by reviewing the elements but won’t be explained here)
Below are the core components that do this. In the project, I first encapsulated this part of logic into a component, below share, this function complete logic (pay attention to the use of vue3+ TS development, do not copy blindly!) :
The component name is tooltipColumn.vue
<! Table overflow hiding component package, used in BaseTable (here refers to the project encapsulated table component), if the use of table components have columns that need to be customized, can also be easily implemented by introducing this component to hide text overflow. -- > <! --1.The number of overflow hidden rows can be set to1,2,3,4Meets project requirements and defaults to exceed2Line overflow (set other nonsense) --> <! --2.If this component is used in custom columns, remember to set the value to the column width, otherwise the number of rows will not count correctly2Line -- -- ><template>
<template v-if="computeOverflow(value, width)">
<el-tooltip placement="top-start" effect="light" :show-after="200">
<template #content>
<div class="tooltip-box">{{ value }}</div>
</template>
<span :class="[`tooltip-text-${overflowRow}`]">{{ value }}</span>
</el-tooltip>
</template>
<span v-else>{{ value }}</span>
</template>
<script lang="ts" setup>
const props = withDefaults(defineProps<{
value: any; width: string | number; overflowRow? : number; {} > (),value: ' '.width: ' '.overflowRow: 2
})
/ * * *@description: Gets the actual width, up to a few characters per line and up to a few lines *@param {*}
* @return {*}* /
const getOverFlowData = (width: string | number) = > {
// Table cell has a total of 20 inner margins and 1px to subtract
const realWidth = parseInt(width as string) - 21
// The maximum number of characters in a line is 6 px.
const rowChar = Math.floor(realWidth / 6)
// Get to display at most a few lines
const row = props.overflowRow
return {
rowChar,
row
}
}
/ * * *@description: Indicates whether tooltip * is displayed@param {*}
* @return {*}* /
const computeOverflow = (val: string, width: string | number): boolean= > {
if (typeofval ! = ='string'| |! width)return false
// The content character length
let len = 0
for (let i = 0; i < val.length; i++) {
const code = val.charCodeAt(i)
len++
// Two characters in Chinese
if (code > 255) {
len++
}
}
const { rowChar, row } = getOverFlowData(width)
// console.log(len, rowChar, row * rowChar)
return row * rowChar < len
}
</script>
<style scoped lang="scss">/ / tooltip style.tooltip-box {
max-width: 600px;
white-space: pre-wrap;
}
.tooltip-text-1..tooltip-text-2..tooltip-text-3..tooltip-text-4 {
display: inline-block;
display: -webkit-box;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
}
.tooltip-text-1 {
-webkit-line-clamp: 1;
}
.tooltip-text-2 {
-webkit-line-clamp: 2;
}
.tooltip-text-3 {
-webkit-line-clamp: 3;
}
.tooltip-text-4 {
-webkit-line-clamp: 4;
}
</style>
Copy the code
This component receives three prop: Value, width, overflowRow representing the value, width, and several lines of overflow hidden. As you can see in the template, the Tooltip component is rendered if overflow hiding is determined, otherwise the text content is displayed normally
How is this component used in a table
The first is how to use it in the table encapsulated in the project. The encapsulated table el-table-column is generated by V-for traversal, that is to say, it only needs to be used in:
Just go in there. You need to receive an overflowRow, indicating that several rows overflow. The default value is 2 rows overflow
// Receive a value from the parent component
props: {
overflowRow: {
type: Number.default: 2}}Copy the code
If you’re using the pure Element table without wrapping it, you can just use it like this
<el-table-column prop="xxx" label="Form item" width="140">
<template #default="{ row }">
<TooltipColumn :value="row.xxx" width="140" />
</template>
</el-table-column>
Copy the code
And you’re done