Skip to content

useTextEllipsis

该 hook 用于获取设置了单行文本超出显示省略号样式的元素的状态(是否显示了省略号)。

实现源码
ts
import { ref, onMounted, onScopeDispose } from 'vue';

const getPadding = (el: HTMLElement) => {
  const style = window.getComputedStyle(el, null);
  const paddingLeft = Number.parseInt(style.paddingLeft, 10) || 0;
  const paddingRight = Number.parseInt(style.paddingRight, 10) || 0;
  const paddingTop = Number.parseInt(style.paddingTop, 10) || 0;
  const paddingBottom = Number.parseInt(style.paddingBottom, 10) || 0;
  return {
    left: paddingLeft,
    right: paddingRight,
    top: paddingTop,
    bottom: paddingBottom
  };
};

const checkEllipsis = (el: HTMLElement) => {
  const { left, right } = getPadding(el);
  const childElement = el.children[0] as HTMLElement;
  if (!childElement) {
    return false;
  }

  const childElementWidth = left + right + childElement.offsetWidth;
  return el.clientWidth <= childElementWidth;
};

/**
 * 文本是否溢出(创建block元素来包裹inline元素)
 * @param isAutoUpdate dom变化后是否自动更新状态(MutationObserver),默认为true
 * @returns
 */
export const useTextEllipsis = (isAutoUpdate = true) => {
  const blockRef = ref<HTMLElement | null>(null);
  const isEllipsis = ref(false);
  const updateStatus = () => {
    if (!blockRef.value) {
      return;
    }

    const element = blockRef.value;
    isEllipsis.value = checkEllipsis(element);
  };

  let observer: MutationObserver | null = null;
  onMounted(() => {
    if (isAutoUpdate) {
      observer = new MutationObserver(updateStatus);
      observer.observe(blockRef.value!, {
        childList: true,
        subtree: true,
        characterData: true
      });
    }

    updateStatus();
  });

  onScopeDispose(() => {
    if (observer) {
      observer.disconnect();
      observer = null;
    }
  });

  return {
    blockRef,
    isEllipsis,
    updateStatus
  };
};

介绍

该 hook 接收一个布尔值参数,用来设置是否自动监听dom元素的变化并变更状态。

返回值为一个对象,包含以下属性:

  • isEllipsis 是否显示了省略号;
  • updateStatus 更新状态函数;
  • blockRef 用于绑定到需要监听的dom元素。

使用

配合ant-design-vuetooltip组件,可以实现文本超出了,才显示完整文字气泡提示的效果。

点我改变文本内容
千山鸟飞绝,万径人踪灭。孤舟蓑笠翁,独钓寒江雪。
示例代码
vue
<script lang="ts" setup>
import { Tooltip } from 'ant-design-vue';
import { ref } from 'vue';
import { useTextEllipsis } from '@utils/hooks/useTextEllipsis';

const { blockRef, isEllipsis } = useTextEllipsis();
const text = ref('千山鸟飞绝,万径人踪灭。孤舟蓑笠翁,独钓寒江雪。');

const onChangeText = () => {
  if (text.value.length > 20) {
    text.value = '大梦一场三百年,人生几度梦中看。';
  } else {
    text.value = '千山鸟飞绝,万径人踪灭。孤舟蓑笠翁,独钓寒江雪。';
  }
};
</script>

<template>
  <div class="text" @click="onChangeText">点我改变文本内容</div>
  <div class="container">
    <tooltip>
      <template v-if="isEllipsis" #title>{{ text }}</template>
      <div ref="blockRef" class="ellipsis">
        <span>{{ text }}</span>
      </div>
    </tooltip>
  </div>
</template>

<style lang="scss" scoped>
.text {
  margin-bottom: 10px;
  cursor: pointer;
  color: #1890ff;
}

.container {
  width: 300px;
}

.ellipsis {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  word-break: break-all;
}
</style>

Released under the MIT License.