likes
comments
collection
share

根据文本是否溢出来控制popover的显示《Javascript 如何获取字符串的宽度》查看年轻时写的代码 效果图如下:

作者站长头像
站长
· 阅读数 21

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

效果图如下:

  1. 单行文本溢出隐藏hover展示全部 根据文本是否溢出来控制popover的显示《Javascript 如何获取字符串的宽度》查看年轻时写的代码 效果图如下:

  2. 多行文本溢出隐藏hover展示全部 根据文本是否溢出来控制popover的显示《Javascript 如何获取字符串的宽度》查看年轻时写的代码 效果图如下:

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

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

// 1. 单行溢出 
.single {   
    overflow: hidden;   
    white-space: nowrap;   
    text-overflow: ellipsis; 
} 
    
    
    
// 2.多行溢出 (需考虑兼容性)
.more {   
    overflow: hidden;   
    text-overflow: ellipsis;
    
    display: -webkit-box;   //必须结合的属性,将对象作为弹性伸缩盒子模型显示 
    -webkit-line-clamp: 2;   //控制文本的行数 
    -webkit-box-orient: vertical;   //必须结合的属性,设置或检索伸缩盒对象的子元素的排列方式 
    
    display: -moz-box;
    -moz-line-clamp: 2;
    -moz-box-orient: vertical;

    display: box;
    line-clamp: 2;
    box-orient: vertical;
}

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

通过直接判断滚动宽度和容器宽度;不需要额外创建临时变量
<template>
    <div class="wrapper">
        <div ref="content" class="content" :title="`${isOverflow ? textStr : ''}`">{{ textStr }}</div>
        <div ref="content2" class="content" :title="`${isOverflow2 ? textStr2 : ''}`">{{ textStr2 }}</div>
    </div>
</template>

<script>
export default {
    data() {
        return {
            textStr: '文本内容是不确定的,11可能超过容器宽度',
            textStr2: '文本内容是确定的',
            isOverflow: false,
            isOverflow2: false,
        }
    },
    mounted() {
        this.judgeOverflow()
    },
  methods: {
      judgeOverflow() {
          const content = this.$refs.content
          this.isOverflow = content.scrollWidth > content.clientWidth

          const content2 = this.$refs.content2
          this.isOverflow2 = content2.scrollWidth > content2.clientWidth
      }
  }
};

</script>

<style lang="scss">
.wrapper {
    position: absolute;
    top: 50%;
    left: 50%;

    .content {
        width: 200px;
        height: auto;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;

        border: 1px solid red;
        border-radius: 4px;

        & + .content {
            margin-top: 20px;
        }
    }
}
</style>

扩展

根据文本是否溢出来控制popover的显示《Javascript 如何获取字符串的宽度》查看年轻时写的代码 效果图如下:

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

const content = this.$refs.content
const {
    scrollWidth,
    clientWidth,
    offsetWidth
} = getComputedStyle(content)
console.log('@@', scrollWidth, clientWidth, offsetWidth);

结果: 根据文本是否溢出来控制popover的显示《Javascript 如何获取字符串的宽度》查看年轻时写的代码 效果图如下:

根据文本是否溢出来控制popover的显示《Javascript 如何获取字符串的宽度》查看年轻时写的代码 效果图如下:

总结: Element.getClientRects()获取的属性如下: 根据文本是否溢出来控制popover的显示《Javascript 如何获取字符串的宽度》查看年轻时写的代码 效果图如下:

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

<template>
    <div class="wrapper">
        <div ref="content" class="content" :title="`${isOverflow ? textStr : ''}`">{{ textStr }}</div>
    </div>
</template>

<script>
export default {
    data() {
        return {
            textStr: 'Window.getComputedStyle()方法返回一个对象,该对象在应用活动样式表并解析这些值可能包含的任何基本计算后报告元素的所有 CSS 属性的值。私有的 CSS 属性值可以通过对象提供的 API 或通过简单地使用 CSS 属性名称进行索引来访问',
            isOverflow: false,
        }
    },
    mounted() {
        this.judgeOverflow()
    },
  methods: {
      judgeOverflow() {
          const content = this.$refs.content
          this.isOverflow = content.scrollHeight > content.clientHeight
      }
  }
};

</script>

<style lang="scss">
.wrapper {
    position: absolute;
    top: 50%;
    left: 50%;

    .content {
        width: 200px;
        height: auto;
        border: 1px solid red;
        border-radius: 4px;

        overflow: hidden;
        text-overflow: ellipsis;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
    }
}
</style>

四、封装为指令调用

<template>
    <div class="wrapper">
        <div ref="content" class="content" v-ellipsis="textStr"></div>
    </div>
</template>

<script>
    import Vue from 'vue';
export default {
    data() {
        return {
            textStr: '一个指令定义对象可以提供bind、inserted、update、componentUpdated、unbind等钩子函数 (均为可选):',
            isOverflow: false,
        }
    },
    directives: {
        ellipsis: {
            bind: (el, binding) => {
                el.innerHTML = binding.value || '';
                // 
                Vue.nextTick(() => {
                    el.title = el.scrollHeight > el.clientHeight ? binding.value : '';
                })
            },
            update: (el, binding) => {
                el.innerHTML = binding.value || '';
                el.title = el.scrollHeight > el.clientHeight ? binding.value : '';
            }
        }

        // 函数简写 在 bind 和 update 时触发相同行为
        // ellipsis(el, binding) {
        //     el.innerHTML = binding.value || '';
        //     Vue.nextTick(() => {
        //         el.title = el.scrollWidth > el.clientWidth ? binding.value : '';
        //     })
        // }
    },
};

</script>

<style lang="scss">
.wrapper {
    position: absolute;
    top: 50%;
    left: 50%;

    .content {
        width: 200px;
        height: auto;
        border: 1px solid red;
        border-radius: 4px;

        overflow: hidden;
        text-overflow: ellipsis;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
    }
}
</style>

五、补充(Node.cloneNode(deep)

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

<template>
    <div class="wrapper">
        <div ref="content" class="content">{{ textStr }}</div>
    </div>
</template>

<script>
export default {
    data() {
        return {
            textStr: '一个指令定义对象可以提供bind、inserted、update、componentUpdated、unbind等钩子函数 (均为可选):',
        }
    },
    mounted() {
        console.log(this.isOverflow());
    },
    methods: {
        isOverflow() {
            const el = this.$refs.content
            const cloneEl = el.cloneNode(true)
            console.log('el:', el.clientHeight, el.scrollHeight, el.style.color);
            console.log('cloneEl:', cloneEl.clientHeight, cloneEl.scrollHeight, cloneEl.style.color);

            if (!(cloneEl instanceof HTMLElement)) {
                return false;
            }
            // 复制节点后,手动将源节点的 `style` 属性值复制到新节点上
            const sourceStyle = window.getComputedStyle(el);
            for(let i = 0; i < sourceStyle.length; i++) {
                const styleName = sourceStyle[i];
                cloneEl.style[styleName] = sourceStyle[styleName];
            }


            document.body.appendChild(cloneEl);
            console.log('getComputedStyle cloneEl:', cloneEl.clientHeight, cloneEl.scrollHeight, cloneEl.style.color);
                    
                    
            // 单行溢出比较 scrollWidth 和 clientWidth
            // 多行溢出比较 scrollHeight 和 clientHeight
            const overflow = cloneEl.scrollWidth > cloneEl.clientWidth || cloneEl.scrollHeight > cloneEl.clientHeight;
            document.body.removeChild(cloneEl);
            return overflow;
        }
    }
};

</script>

<style lang="scss">
.wrapper {
    position: absolute;
    top: 50%;
    left: 50%;

    .content {
        width: 200px;
        height: auto;
        border: 1px solid red;
        border-radius: 4px;
        color: #ccc;

        overflow: hidden;
        text-overflow: ellipsis;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
    }
}
</style>

如图: 根据文本是否溢出来控制popover的显示《Javascript 如何获取字符串的宽度》查看年轻时写的代码 效果图如下:

转载自:https://juejin.cn/post/7407275971901980726
评论
请登录