Vue - 多行文本“展开、收起”功能

2024-01-03 09:36:39

TextClamp

使用 js 实现文本展开、收起,并非纯 CSS 实现。

Props:

  • fontSize:Number,默认:14
  • lines:Number,默认:1
  • lineHeight:Number,默认:20

Feat:

  • 监听插槽的变化(文本内容的变化),自动计算文本高度
  • 展开、折叠时有 transition 效果
  • 文本内容较少时(未超过行数 lines),不会展示按钮

Code

text-clamp.vue


 <template>
  <div class="text-clamp">
    <div class="text" :style="{height}">
      <span v-if="isVisible" class="btn" @click="toggle">{{isExpand ? '收起' : '... 展开'}}</span>
      <div ref="textRef" :style="commonStyle">
        <slot />
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "TextClamp",
  props: {
    fontSize: {
      type: Number,
      default: 14
    },
    lines: {
      type: Number,
      default: 1
    },
    lineHeight: {
      type: Number,
      default: 20
    },
    selectors: {
      type: String,
      default: ""
    }
  },
  data () {
    return {
      isExpand: false,
      isVisible: false,
      textHeight: 0
    }
  },
  computed: {
    height () {
      if (this.isExpand) {
        return this.$refs.textRef.clientHeight + 'px';
      } else {
        return Math.min((this.lines * this.lineHeight), this.textHeight) + 'px';
      }
    },
    commonStyle () {
      return {
        lineHeight: this.lineHeight + 'px',
        fontSize: this.fontSize + 'px',
      }
    }
  },
  mounted () {
    this.init();
    // 监听插槽变化
    const observer = new MutationObserver((mutations) => {
      mutations.forEach((mutation) => {
        if (mutation.type === "characterData") {
          this.init();
        }
      });
    });
    observer.observe(this.$refs.textRef, {
      characterData: true,
      subtree: true,
      childList: true
    });
  },
  methods: {
    init () {
      this.isExpand = false;
      this.textHeight = this.$refs?.textRef?.clientHeight || 0;
      this.isVisible = this.textHeight > this.lines * this.lineHeight;
    },
    toggle () {
      this.isExpand = !this.isExpand;
      if (!this.isExpand && this.selectors) {
        const initEl = document.querySelector(this.selectors);
        setTimeout(() => {
          initEl.scrollIntoView({
            behavior: 'smooth',
            block: 'start',
            inline: 'center'
          });
        }, 97)
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.text-clamp {
  display: flex;
  overflow: hidden;
}
.text {
  font-size: 20px;
  transition: 0.3s height;
}
.text::before {
  content: "";
  height: calc(100% - 20px);
  float: right;
}
.btn {
  float: right;
  clear: both;
  font-size: 12px;
  line-height: 14px;
  padding: 2px 6px;
  background: #1890ff;
  border-radius: 2px;
  color: #fff;
  cursor: pointer;
}
</style>

实例

<div style="min-height: 120px;">
    <text-clamp :lines="6">123123</text-clamp>
</div>
<text-clamp :lines="5" :line-height="24">{{data || "--"}}</text-clamp>

文章来源:https://blog.csdn.net/qq_36157085/article/details/134593956
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。