封装ellipsis组件

element-ui表单内tooltip可以让文字超出单元格时显示气泡,但是有一个限制,只能显示纯文本,无法控制tooptip内的样式,即使传入带标签的文本,也会把文本过滤出来,难以满足ui要求。

于是借用el-poper来实现,又有一个缺点,无论文字是否超出都会展示气泡,最后决定自己封装一个ellipsis组件,当元素内的文本超出元素展示省略号时,出现气泡。

思路:鼠标移入元素,比较元素的scrollHeight与clientHeight的大小,若滚动高度大于固定显示宽度,则文本是溢出状态。溢出状态时,创建气泡元素,计算好位置。

创建一个ellipsis组件:

<template>
  <div
    class="sllipsis-wraper"
    :style="{ '-webkit-line-clamp': lineClamp }"
    @mouseenter="mouseenter($event)"
    @mouseleave="mouseleave($event)"
  >
    <slot></slot>
  </div>
</template>

<script>
export default {
  name: "ellipsis",
  props: {
    lineClamp: {
      //展示几行
      type: Number,
      default: 1
    },
    tipText: {
      //提示值
      type: Array | String,
      default: ""
    }
  },
  computed: {
    bubbleId() {
      return `sllipsis-bubble-${this._uid}`;
    },
    htmlStr() {
      if (Array.isArray(this.tipText)) {
        let str = "";
        this.tipText.forEach(item => {
          str += `<span class="bublle-span">${item}</span>`;
        });
        return str;
      } else {
        return this.tipText;
      }
    }
  },
  data() {
    return {};
  },
  created() {},
  methods: {
    mouseenter(e) {
      //鼠标移入
      if (!this.tipText.length) return;
      var target = e.target,
        containerHeight = target.clientHeight,
        textHeight = target.scrollHeight,
        positionObj = target.getBoundingClientRect(),
        windowHeight = window.innerHeight,
        showLocation =
          windowHeight - positionObj.bottom < 50 ? "top" : "bottom";
      if (textHeight > containerHeight) {
        //溢出
        this.showBubble({
          htmlStr: this.htmlStr,
          position: positionObj,
          showLocation: showLocation
        });
      } else {
        //未溢出
        this.hideBubble();
      }
    },
    mouseleave(e) {
      //鼠标移开
      this.hideBubble();
    },
    createBubbleElement(data) {
      //创建提示框
      let { htmlStr, position, showLocation } = data;
      if (!document.getElementById(this.bubbleId)) {
        let nodeEle = document.createElement("div");
        nodeEle.id = this.bubbleId;
        this.setBubbleLocation(nodeEle,data);
        this.setBubbleContent(nodeEle,htmlStr);
        nodeEle.classList.add("is-block");
        document.body.appendChild(nodeEle);
      }
    },
    hideBubble() {
      // 隐藏提示框
      let bubbleNode = this.getBubbleEle();
      if (bubbleNode) {
        bubbleNode.classList.remove("is-block");
      }
    },
    showBubble(data) {
      // 展示提示框
      let bubbleNode = this.getBubbleEle();
      if (bubbleNode) {
        this.setBubbleLocation(bubbleNode,data);
        this.setBubbleContent(bubbleNode,data.htmlStr);
        bubbleNode.classList.add("is-block");
      } else {
        //创建
        this.createBubbleElement(data);
      }
    },
    getBubbleEle() {
      //获取提示框元素
      return document.getElementById(this.bubbleId);
    },
    setBubbleLocation(DOM,data){
      // 设置气泡位置
      let { htmlStr, position, showLocation } = data;
        DOM.classList.add("is-block");
        if (showLocation == "top") {
          DOM.style.top = "";
          DOM.style.bottom = window.innerHeight - position.top + "px";
          DOM.className = `sllipsis-bubble is-top`;
          DOM.style.setProperty('--bubble-allow-y', -12 + "px");
        } else {
          DOM.style.bottom  = "";
          DOM.style.top = position.bottom + "px";
          DOM.className = `sllipsis-bubble is-bottom`;
          DOM.style.setProperty('--bubble-allow-y', -12 + "px");
        }
        DOM.style.left = position.left + "px";
        DOM.style.setProperty('--bubble-allow-x', position.width/2 + "px");
        
    },
    setBubbleContent(DOM,content){
      // 设置气泡内容
      DOM.innerHTML = content;
    }
  }
};
</script>

<style lang="scss">
.sllipsis-wraper {
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-box-orient: vertical;
}
.sllipsis-bubble {
  position: fixed;
  max-width: 400px;
  background: #fff;
  border-radius: 4px;
  border: 1px solid #e4e6e9;
  padding: 6px;
  color: #333940;
  line-height: 1.4;
  font-size: 14px;
  box-shadow: 0 2px 4px 0 #e4e6e9;
  word-break: break-all;
  // z-index: 1;
  display: none;
  box-sizing: border-box;
  &::before {
    content: "";
    position: absolute;
    width: 0;
    height: 0;
    border-width: 6px;
    border-style: solid;
    border-radius: 2px;
    z-index:2;
    left:var(--bubble-allow-x)
  }
  &.is-top::before{
    bottom:var(--bubble-allow-y);
    border-color: #fff transparent transparent transparent;
  }
  &.is-bottom::before{
    top:var(--bubble-allow-y);
    border-color: transparent transparent #fff transparent;
  }
  &.is-block {
    display: block;
  }
  &:hover {
    display: block;
  }
  .bublle-span {
    display: inline-block;
    border: 1px solid #e4e6e9;
    font-size: 12px;
    text-align: left;
    color: #333940;
    line-height: 18px;
    border-radius: 2px;
    margin-right: 4px;
    margin-top: 3px;
    margin-bottom: 3px;
    padding: 1px 2px;
  }
}
</style>

使用方法:

<ellipsis :lineClamp="1" tipText="xxx">
        {{xxx}}
</ellipsis>
                           

超出一行隐藏时可省略lineClamp属性

效果:

原文地址:https://www.cnblogs.com/fqh123/p/15106530.html