# 三.数据输出(文本溢出)
前言
文本溢出组件
# 1.目录结构
├── text-overflow
│ ├── overflow.vue
│ └── index.js
1
2
3
2
3
# 2.组件封装
- 源代码
<template>
<div class="wrapper">
<input id="textOverflow" class="text-overflow" type="checkbox" />
<div class="text">
<label class="btn" for="textOverflow"></label>
{{ text }}
</div>
</div>
<!-- <div class="wrapper">
<input id="text-overflow2" class="text-overflow" type="checkbox" />
<div class="text">
<label class="btn" for="text-overflow2"></label>
浮动元素是如何定位的
正如我们前面提到的那样,当一个元素浮动之后,它会被移出正常的文档流,然后向左或者向右平移,一直平移直到碰到了所处的容器的边框,或者碰到另外一个浮动的元素。
</div>
</div> -->
</template>
<script>
export default {
name: "TextOverflow",
props: {
text: {
type: String,
default: "",
},
},
};
</script>
<style lang="scss" scoped>
.wrapper {
display: flex;
margin: 50px auto;
width: auto;
max-width: 800px;
overflow: hidden;
border-radius: 8px;
padding: 15px;
box-shadow: 20px 20px 60px #bebebe, -20px -20px 60px #ffffff;
}
.text {
font-size: 20px;
overflow: hidden;
text-overflow: ellipsis;
text-align: justify;
/* display: flex; */
/* display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical; */
position: relative;
line-height: 1.5;
max-height: 4.5em;
transition: 0.3s max-height;
}
.text::before {
content: "";
height: calc(100% - 26px);
float: right;
}
.text::after {
content: "";
width: 999vw;
height: 999vw;
position: absolute;
box-shadow: inset calc(100px - 999vw) calc(30px - 999vw) 0 0 #fff;
margin-left: -100px;
}
.btn {
position: relative;
float: right;
clear: both;
margin-left: 20px;
font-size: 16px;
padding: 0 8px;
background: #3f51b5;
line-height: 24px;
border-radius: 4px;
color: #fff;
cursor: pointer;
/* margin-top: -30px; */
}
.btn::after {
content: "展开";
}
.text-overflow {
display: none;
}
.text-overflow:checked + .text {
max-height: 200px;
}
.text-overflow:checked + .text::after {
visibility: hidden;
}
.text-overflow:checked + .text .btn::before {
visibility: hidden;
}
.text-overflow:checked + .text .btn::after {
content: "收起";
}
.btn::before {
content: "...";
position: absolute;
left: -5px;
color: #333;
transform: translateX(-100%);
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
1.兼容问题
display: -webkit-box;
1在一些浏览器上有兼容性问题,导致不能使用
display: flex; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
1
2
3
4使用替代方式来实现文字溢出效果
line-height: 1.5; max-height: 4.5em;
1
2
<template>
<div class="c-text-hide">
<input
:id="`group-members_exp${itemData.id}`"
class="group_class"
type="checkbox"
/>
<div :ref="`content${itemData.id}`" class="more-text">
<label
v-if="itemData.isExpand"
class="more-btn cur"
:for="`group-members_exp${itemData.id}`"
@click="handleToggleChange($event, itemData)"
>
<span class="text">{{ itemData.isShow ? "收起" : "展开" }}</span>
<i class="el-icon-arrow-down" />
</label>
{{ itemData.content }}
<span v-if="itemData.isShow"
> </span
>
</div>
</div>
</template>
<script>
export default {
name: "TextOverflow2",
props: {
textData: {
type: Object,
default: () => {
return {};
},
},
lineNumber: {
type: Number,
default: 3,
},
},
data() {
return {
lineHeight: 31,
itemData: {},
};
},
mounted() {
this.itemData = Object.assign({}, { ...this.textData });
this.summaryHeight(this.itemData);
},
methods: {
getFontSize(data) {
return (window.innerWidth / 1920) * data * 100;
},
handleToggleChange(event, val) {
val.isShow = !val.isShow;
this.itemData = Object.assign({}, this.itemData, { ...val });
this.$emit("toggleChange", this.itemData);
},
getWidth(txt, widht) {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
ctx.font = this.getFontSize(0.24) + "px Arial";
return ctx.measureText(txt).width;
},
textline(txt, width) {
const font = this.getFontSize(0.24) + "px";
if (txt) {
const txts = txt.split("\n");
let line = 0;
for (var key in txts) {
line += Math.ceil(this.getWidth(txts[key], font) / width);
}
return line;
}
},
summaryHeight(itemData) {
this.$nextTick(() => {
const lineWidth = this.$refs[`content${itemData.id}`].clientWidth;
const txt = this.$refs[`content${itemData.id}`].innerText;
const width = this.getWidth(txt, "24px");
const line = this.textline(txt, lineWidth);
if (line >= this.lineNumber) {
if (width > this.lineNumber * lineWidth - 100) {
this.itemData = Object.assign({}, this.itemData, {
isExpand: true,
});
} else {
this.itemData = Object.assign({}, this.itemData, {
isExpand: false,
});
}
}
this.$emit("toggleChange", this.itemData);
});
},
},
};
</script>
<style lang="scss" scoped>
.c-text-hide {
display: flex;
font-size: 24px;
width: 100%;
.more-text {
width: 100%;
font-size: 24px;
overflow: hidden;
line-height: 1.3;
position: relative;
white-space: normal;
word-break: break-all;
word-wrap: break-word;
text-align: justify;
line-break: anywhere;
width: 100%;
text-overflow: ellipsis;
-webkit-line-clamp: 6;
display: -webkit-box;
-webkit-box-orient: vertical;
position: relative;
.more-btn {
position: absolute;
bottom: 0;
right: 0;
background-image: linear-gradient(
88.05deg,
rgba(255, 255, 255, 0) 0%,
#fff 25%,
#fff 100%
);
&::before {
content: "...";
margin-right: 8px;
margin-left: 40px;
transform: translateX(-100%);
}
.text {
color: #7583c9;
font-size: 24px;
cursor: pointer;
}
.el-icon-arrow-down::before {
font-size: 16px;
margin-right: 3px;
}
}
}
.group_class {
display: none;
&:checked + .more-text {
-webkit-line-clamp: 999;
max-height: none !important;
}
&:checked + .more-text .more-btn {
margin-top: -12px;
.text {
color: #7583c9;
font-size: 24px;
}
}
&:checked + .more-text .more-btn .el-icon-arrow-down {
transform: rotate(180deg);
}
&:checked + .more-text .more-btn::before {
display: none;
}
&:checked + .more-text::after {
display: none;
}
}
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# 3.使用案例
# 3.1 组件1
刷新
全屏/自适应
刷新
全屏/自适应
# 3.2 组件2
刷新
全屏/自适应