<template>
   <div ref="ellipsisDom" class="ellipsis" :key="ellipsisData.key" :class="{ vis: !ellipsisData.computedReady }">
      <span ref="textDom">{{ text }}</span>
      <span v-show="ellipsisData.oversize && !ellipsisData.expanded">...</span>
      <span v-show="ellipsisData.oversize" class="ellipsisAct" @click="handleExpand">{{ ellipsisData.expanded ? "收起" : "展开" }}</span>
   </div>
</template>

<script>
export default {
   name: "TextEllipsis",
   data() {
      return {
         ellipsisData: {
            oversize: false,
            computedReady: false, // 先隐形计算，计算好后，再根据配置显示
            expanded: false,
            key: 0
         }
      }
   },
   props: {
      text: {
         type: String
      },
      lines: {
         type: Number,
         default: 2 // 默认显示的行数
      }
   },
   watch: {
      text() {
         // 强制刷新组件
         this.ellipsisData.key++
         this.ellipsisData.expanded = false
         this.computeText()
      }
   },
   created() {
      this.computeText()
   },
   methods: {
      getStyle(el, styleName) {
         if (!el) return ""
         if (styleName === "float") {
            styleName = "cssFloat"
         }
         try {
            const style = el.style[styleName]
            if (style) return style
            const computed = document.defaultView?.getComputedStyle(el, "")
            return computed ? computed[styleName] : ""
         } catch {
            return el.style[styleName]
         }
      },
      computeText() {
         this.ellipsisData.oversize = false
         this.ellipsisData.computedReady = false
         this.$nextTick(() => {
            let text = this.text
            let height = 0
            const lines = this.lines
            const ellipsisDom = this.$refs.ellipsisDom
            const textDom = this.$refs.textDom
            if (this.ellipsisData.expanded) {
               textDom.innerText = this.text
               this.ellipsisData.oversize = true
               this.ellipsisData.computedReady = true
               return
            }
            if (!height && lines) {
               const lineHeight = parseInt(this.getStyle(ellipsisDom, "lineHeight"))
               height = lineHeight * lines
            }
            if (ellipsisDom.offsetHeight > height) {
               this.ellipsisData.oversize = true
               this.$nextTick(() => {
                  while (ellipsisDom.offsetHeight > height) {
                     if (ellipsisDom.offsetHeight > height * 3) {
                        textDom.innerText = text = text.substring(0, Math.floor(text.length / 2))
                     } else {
                        textDom.innerText = text = text.substring(0, text.length - 1)
                     }
                  }
               })
            }
            this.ellipsisData.computedReady = true
         })
      },
      handleExpand() {
         this.ellipsisData.expanded = !this.ellipsisData.expanded
         this.computeText()
      }
   }
}
</script>

<style lang="less" scoped>
.ellipsis {
   line-height: 0.2rem;
   &.vis {
      visibility: hidden;
   }
   .ellipsisAct {
      cursor: pointer;
      color: #14e0d3;
      font-weight: 500;
      margin-left: 2px;
   }
}
</style>
