前言:之前遇到一个需求:单行文本溢出隐藏hover展示全部,当时写过一篇文章,是创建一个临时变量,然后设置样式,通过比较文本正常的宽度和布局宽度来判断是否溢出;现在遇到另一个需求,多行文本溢出隐藏hover展示全部信息;回想起当初的写法,只能说是年轻时“不懂事”啊,现在这两种场景重新进行梳理总结

《Javascript 如何获取字符串的宽度》查看年轻时写的代码

效果图如下:

  1. 单行文本溢出隐藏hover展示全部

  2. 多行文本溢出隐藏hover展示全部

我们就以title属性来代替popover效果,实现代码如下:

一、 控制文本溢出隐藏 css实现非常简单

 1// 1. 单行溢出 
 2.single {   
 3    overflowhidden;   
 4    white-spacenowrap;   
 5    text-overflowellipsis; 
 6} 
 7    
 8    
 9    
10// 2.多行溢出 (需考虑兼容性)
11.more {   
12    overflowhidden;   
13    text-overflowellipsis;
14    
15    display: -webkit-box;   //必须结合的属性,将对象作为弹性伸缩盒子模型显示 
16    -webkit-line-clamp: 2;   //控制文本的行数 
17    -webkit-box-orient: vertical;   //必须结合的属性,设置或检索伸缩盒对象的子元素的排列方式 
18    
19    display: -moz-box;
20    -moz-line-clamp: 2;
21    -moz-box-orient: vertical;
22
23    display: box;
24    line-clamp: 2;
25    box-orient: vertical;
26}

二、 JS判断单行文本是否溢出

 1通过直接判断滚动宽度和容器宽度不需要额外创建临时变量
 1<template>
 2    <div class="wrapper">
 3        <div ref="content" class="content" :title="`${isOverflow ? textStr : ''}`">{{ textStr }}</div>
 4        <div ref="content2" class="content" :title="`${isOverflow2 ? textStr2 : ''}`">{{ textStr2 }}</div>
 5    </div>
 6</template>
 7
 8<script>
 9export default {
10    data() {
11        return {
12            textStr: '文本内容是不确定的,11可能超过容器宽度',
13            textStr2: '文本内容是确定的',
14            isOverflow: false,
15            isOverflow2: false,
16        }
17    },
18    mounted() {
19        this.judgeOverflow()
20    },
21  methods: {
22      judgeOverflow() {
23          const content = this.$refs.content
24          this.isOverflow = content.scrollWidth > content.clientWidth
25
26          const content2 = this.$refs.content2
27          this.isOverflow2 = content2.scrollWidth > content2.clientWidth
28      }
29  }
30};
31
32</script>
33
34<style lang="scss">
35.wrapper {
36    position: absolute;
37    top: 50%;
38    left: 50%;
39
40    .content {
41        width: 200px;
42        height: auto;
43        white-space: nowrap;
44        overflow: hidden;
45        text-overflow: ellipsis;
46
47        border: 1px solid red;
48        border-radius: 4px;
49
50        & + .content {
51            margin-top: 20px;
52        }
53    }
54}
55</style>

扩展

总结: getComputedStyle(# Element) 能获取到所有的css属性,但是获取不到 offsetWidth 、clientWidth、scrollWidth等

 1const content = this.$refs.content
 2const {
 3    scrollWidth,
 4    clientWidth,
 5    offsetWidth
 6} = getComputedStyle(content)
 7console.log('@@', scrollWidth, clientWidth, offsetWidth);

结果:

总结: Element.getClientRects()获取的属性如下:

三、 JS判断多行文本是否溢出

 1<template>
 2    <div class="wrapper">
 3        <div ref="content" class="content" :title="`${isOverflow ? textStr : ''}`">{{ textStr }}</div>
 4    </div>
 5</template>
 6
 7<script>
 8export default {
 9    data() {
10        return {
11            textStr: 'Window.getComputedStyle()方法返回一个对象,该对象在应用活动样式表并解析这些值可能包含的任何基本计算后报告元素的所有 CSS 属性的值。私有的 CSS 属性值可以通过对象提供的 API 或通过简单地使用 CSS 属性名称进行索引来访问',
12            isOverflow: false,
13        }
14    },
15    mounted() {
16        this.judgeOverflow()
17    },
18  methods: {
19      judgeOverflow() {
20          const content = this.$refs.content
21          this.isOverflow = content.scrollHeight > content.clientHeight
22      }
23  }
24};
25
26</script>
27
28<style lang="scss">
29.wrapper {
30    position: absolute;
31    top: 50%;
32    left: 50%;
33
34    .content {
35        width: 200px;
36        height: auto;
37        border: 1px solid red;
38        border-radius: 4px;
39
40        overflow: hidden;
41        text-overflow: ellipsis;
42        display: -webkit-box;
43        -webkit-line-clamp: 2;
44        -webkit-box-orient: vertical;
45    }
46}
47</style>

四、封装为指令调用

 1<template>
 2    <div class="wrapper">
 3        <div ref="content" class="content" v-ellipsis="textStr"></div>
 4    </div>
 5</template>
 6
 7<script>
 8    import Vue from 'vue';
 9export default {
10    data() {
11        return {
12            textStr: '一个指令定义对象可以提供bind、inserted、update、componentUpdated、unbind等钩子函数 (均为可选):',
13            isOverflow: false,
14        }
15    },
16    directives: {
17        ellipsis: {
18            bind: (el, binding) => {
19                el.innerHTML = binding.value || '';
20                
21                Vue.nextTick(() => {
22                    el.title = el.scrollHeight > el.clientHeight ? binding.value : '';
23                })
24            },
25            update: (el, binding) => {
26                el.innerHTML = binding.value || '';
27                el.title = el.scrollHeight > el.clientHeight ? binding.value : '';
28            }
29        }
30
31        
32        
33        
34        
35        
36        
37        
38    },
39};
40
41</script>
42
43<style lang="scss">
44.wrapper {
45    position: absolute;
46    top: 50%;
47    left: 50%;
48
49    .content {
50        width: 200px;
51        height: auto;
52        border: 1px solid red;
53        border-radius: 4px;
54
55        overflow: hidden;
56        text-overflow: ellipsis;
57        display: -webkit-box;
58        -webkit-line-clamp: 2;
59        -webkit-box-orient: vertical;
60    }
61}
62</style>

五、补充(Node.cloneNode(deep)

Node.cloneNode()  方法返回调用该方法的节点的一个副本。
该方法不会自动复制通过外部 CSS 文件或内嵌 <style> 标签定义的样式,这是因为它只是复制了节点的结构,而不是与之相关的样式信息。eg:

 1<template>
 2    <div class="wrapper">
 3        <div ref="content" class="content">{{ textStr }}</div>
 4    </div>
 5</template>
 6
 7<script>
 8export default {
 9    data() {
10        return {
11            textStr: '一个指令定义对象可以提供bind、inserted、update、componentUpdated、unbind等钩子函数 (均为可选):',
12        }
13    },
14    mounted() {
15        console.log(this.isOverflow());
16    },
17    methods: {
18        isOverflow() {
19            const el = this.$refs.content
20            const cloneEl = el.cloneNode(true)
21            console.log('el:', el.clientHeight, el.scrollHeight, el.style.color);
22            console.log('cloneEl:', cloneEl.clientHeight, cloneEl.scrollHeight, cloneEl.style.color);
23
24            if (!(cloneEl instanceof HTMLElement)) {
25                return false;
26            }
27            
28            const sourceStyle = window.getComputedStyle(el);
29            for(let i = 0; i < sourceStyle.length; i++) {
30                const styleName = sourceStyle[i];
31                cloneEl.style[styleName] = sourceStyle[styleName];
32            }
33
34
35            document.body.appendChild(cloneEl);
36            console.log('getComputedStyle cloneEl:', cloneEl.clientHeight, cloneEl.scrollHeight, cloneEl.style.color);
37                    
38                    
39            
40            
41            const overflow = cloneEl.scrollWidth > cloneEl.clientWidth || cloneEl.scrollHeight > cloneEl.clientHeight;
42            document.body.removeChild(cloneEl);
43            return overflow;
44        }
45    }
46};
47
48</script>
49
50<style lang="scss">
51.wrapper {
52    position: absolute;
53    top: 50%;
54    left: 50%;
55
56    .content {
57        width: 200px;
58        height: auto;
59        border: 1px solid red;
60        border-radius: 4px;
61        color: #ccc;
62
63        overflow: hidden;
64        text-overflow: ellipsis;
65        display: -webkit-box;
66        -webkit-line-clamp: 2;
67        -webkit-box-orient: vertical;
68    }
69}
70</style>

如图:

个人笔记记录 2021 ~ 2025