15.vue 中如何控制文本多行展开收缩功能

书诚小驿2024/12/24前端知识库Vue3

1、textEllipsis.vue 组件

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

<script>
  export default {
    name: "TextClamp",
    props: {
      fontSize: {
        type: String,
        default: "16",
      },
      lines: {
        type: String,
        default: "1",
      },
      lineHeight: {
        type: String,
        default: "22",
      },
      selectors: {
        type: String,
        default: "",
      },
    },
    data() {
      return {
        isExpand: false,
        isVisible: false,
        textHeight: 0,
      };
    },
    computed: {
      height() {
        if (this.isExpand) {
          return this.$refs.textRef.clientHeight + "px";
        }
        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: 15px;
    line-height: 22px;
    color: var(--text_black_lv2);
    cursor: pointer;
    .btn-pic {
      width: 13px;
      height: 13px;
      margin-left: 3px;
    }
  }
  .ellipsis {
    color: var(--text_black_lv1) !important;
  }
</style>

2、引用组件

<template>
  <div>
    <text-ellipsis lines="3" lineHeight="22" fontSize="16">
      此处写下你的多行文本内容
    </text-ellipsis>
  </div>
</template>

<script setup>
  import TextEllipsis from "@/components/TextEllipsis";
</script>

<style scoped lang="scss"></style>
最后更新时间' 2025/1/3 14:16:58