Vue 多行文本溢出隐藏显示省略号后更多和收起

1,369 阅读1分钟

需求

文本超出后需要显示省略号并且省略号后面需要有更多和收起按钮的功能

实现思路

文本.... 更多 都放在一个容器内,计算容器的 scrollHeightclientHeight,这里面需要不断从 文本 的最后开始删减字符,知道删减的字符和 ... 更多 加起来更好是你需要显示的行数,为了之后还原 文本 所以还需要备份一下 文本,至于怎么一个个删减字符达到刚好的行数这里面需要用到递归。下面呢是我实现的代码

代码

<template>
  <div class="typography" :class="{ isMore: isMore && isPackUp }">
    <div class="text multi-text" :class="{ showAll: isMore }" ref="multi">
      {{ description }}
      <span v-if="isSuffix && !isMore">....</span>
      <span class="text more" v-if="isSuffix && !isMore" @click="reset">
        {{ $t('more') }}
      </span>
      <div class="text more pack-up" v-if="isMore && isPackUp" @click="packUp">
        {{ $t('packUp') }}
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      isSuffix: false,
      isMore: false,
      isPackUp: false,
      count: 0,
      description: this.$t('typography'),
      originDesc: this.$t('typography'),
    }
  },
  mounted() {
    this.computeDesc()
    window.addEventListener('resize',this.onResize)
  },
  beforeDestroy(){
    window.removeEventListener('resize',this.onResize)
  },
  methods: {
    onResize(){
      this.description = this.originDesc
      this.isSuffix = false
      this.isMore = false
      this.isPackUp = false
      this.computeDesc()
    },
    // 计算 description 的高度
    getDescHeight() {
      let heightObj = {}
      this.$nextTick(() => {
        let multi = this.$refs.multi
        // console.log(multi)
        if (multi) {
          console.log('scrollHeight', multi.scrollHeight)
          console.log('clientHeight', multi.clientHeight)
          heightObj.scrollHeight = multi.scrollHeight
          heightObj.clientHeight = multi.clientHeight
        }
      })
      return heightObj
    },
    // 从后往前删减 description 的字符
    async computeDesc() {
      const heightObj = await this.getDescHeight()
      // console.log('height', heightObj)
      const { scrollHeight, clientHeight } = heightObj
      if (this.count === 0 && scrollHeight === clientHeight) {
        this.isMore = true
        this.isPackUp = false
        return
      }
      if (scrollHeight > clientHeight) {
        this.description = this.description.slice(
          0,
          this.description.length - 1
        )
        // console.log('description', this.tokenDetail.description)
        this.count++
        this.isSuffix = true
        this.computeDesc()
      }
    },
    packUp() {
      this.isMore = false
      this.isPackUp = false
      this.computeDesc()
    },
    reset() {
      this.description = this.originDesc
      this.isMore = true
      this.isPackUp = true
    },
  },
}
</script>

<style lang="scss" scoped>
.typography {
  padding: 0.2rem 0.32rem;
  border: 0.01rem solid #999;
  border-radius: 0.16rem;
  &.isMore {
    padding: 0.2rem 0.32rem 0.38rem;
  }
  position: relative;
  .multi-text {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 4;
    overflow: hidden;
    &.showAll {
      -webkit-line-clamp: 999;
    }
    .more {
      cursor: pointer;
      color: #2980fe;
    }
    .pack-up {
      position: absolute;
      right: 0.42rem;
      bottom: 0.1rem;
    }
  }
}
</style>

也可以在codepen预览 codepen.io/ycg5250/pen… 至于宽度改变之后, 可以用 window.onresize来监听窗口的大小变化,不过这个我只是测试了一下还行,也可以去掉。