Vue3文本省略(Ellipsis)

简介: 这是一个基于Vue3的文本省略组件(Ellipsis),支持单行或多行文本的自动省略与展开功能,并可自定义提示框(Tooltip)的内容与样式。

效果如下图:在线预览

在这里插入图片描述

APIs

Ellipsis

参数 说明 类型 默认值
maxWidth 文本最大宽度,单位 px number | string ‘100%’
line 最大行数 number undefined
expand 是否启用点击文本展开全部 boolean false
tooltip 是否启用文本提示框 boolean true
tooltipProps Tooltip 组件属性配置,参考 Tooltip Props object {}

Events

名称 说明 类型
expandChange 点击文本展开收起时的回调 (expand: boolean) => void

创建文本省略组件Ellipsis.vue

其中引入使用了以下组件和工具函数:

<script setup lang="ts">
import { ref, computed, watch, onMounted, nextTick } from 'vue'
import Tooltip from '../tooltip'
import { useResizeObserver } from '../utils'
interface Props {
  maxWidth?: string | number // 文本最大宽度,单位 px
  line?: number // 最大行数
  expand?: boolean // 是否启用点击文本展开全部
  tooltip?: boolean // 是否启用文本提示框
  tooltipProps?: object // Tooltip 组件属性配置,参考 Tooltip Props
}
const props = withDefaults(defineProps<Props>(), {
  maxWidth: '100%',
  line: undefined,
  expand: false,
  tooltip: true,
  tooltipProps: () => ({})
})
const showTooltip = ref(false) // 是否显示提示框
const showExpand = ref(false) // 是否可以启用点击展开
const ellipsisRef = ref()
const defaultTooltipMaxWidth = ref()
const textMaxWidth = computed(() => {
  if (typeof props.maxWidth === 'number') {
    return props.maxWidth + 'px'
  }
  return props.maxWidth
})
watch(
  () => [props.maxWidth, props.line, props.tooltip],
  () => {
    if (props.tooltip) {
      showTooltip.value = getTooltipShow()
    }
  },
  {
    deep: true,
    flush: 'post'
  }
)
useResizeObserver(ellipsisRef, () => {
  if (props.tooltip) {
    showTooltip.value = getTooltipShow()
  }
})
onMounted(() => {
  if (props.tooltip) {
    showTooltip.value = getTooltipShow()
  }
})
function getTooltipShow() {
  const scrollWidth = ellipsisRef.value.scrollWidth
  const scrollHeight = ellipsisRef.value.scrollHeight
  const clientWidth = ellipsisRef.value.clientWidth
  const clientHeight = ellipsisRef.value.clientHeight
  if (scrollWidth > clientWidth || scrollHeight > clientHeight) {
    defaultTooltipMaxWidth.value = ellipsisRef.value.offsetWidth + 24
    if (props.expand) {
      showExpand.value = true
    }
    return true
  } else {
    if (props.expand) {
      showExpand.value = false
    }
    return false
  }
}
const emit = defineEmits(['expandChange'])
function onExpand() {
  if (ellipsisRef.value.style['-webkit-line-clamp']) {
    if (props.tooltip) {
      showTooltip.value = false
      nextTick(() => {
        ellipsisRef.value.style['-webkit-line-clamp'] = ''
      })
    } else {
      ellipsisRef.value.style['-webkit-line-clamp'] = ''
    }
    emit('expandChange', true)
  } else {
    if (props.tooltip) {
      showTooltip.value = true
    }
    ellipsisRef.value.style['-webkit-line-clamp'] = props.line
    emit('expandChange', false)
  }
}
</script>
<template>
  <Tooltip
    v-if="showTooltip"
    :max-width="defaultTooltipMaxWidth"
    :tooltip-style="{ padding: '8px 12px', textAlign: 'justify' }"
    v-bind="tooltipProps"
  >
    <template #tooltip>
      <slot name="tooltip">
        <slot></slot>
      </slot>
    </template>
    <div
      ref="ellipsisRef"
      class="m-ellipsis"
      :class="[line ? 'ellipsis-line' : 'not-ellipsis-line', { 'ellipsis-cursor-pointer': showExpand }]"
      :style="`-webkit-line-clamp: ${line}; max-width: ${textMaxWidth};`"
      @click="showExpand ? onExpand() : () => false"
      v-bind="$attrs"
    >
      <slot></slot>
    </div>
  </Tooltip>
  <div
    v-else
    ref="ellipsisRef"
    class="m-ellipsis"
    :class="[line ? 'ellipsis-line' : 'not-ellipsis-line', { 'ellipsis-cursor-pointer': showExpand }]"
    :style="`-webkit-line-clamp: ${line}; max-width: ${textMaxWidth};`"
    @click="showExpand ? onExpand() : () => false"
    v-bind="$attrs"
  >
    <slot></slot>
  </div>
</template>
<style lang="less" scoped>
.m-ellipsis {
  overflow: hidden;
  cursor: text;
}
.ellipsis-line {
  display: -webkit-inline-box;
  -webkit-box-orient: vertical;
}
.not-ellipsis-line {
  display: inline-block;
  vertical-align: bottom;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.ellipsis-cursor-pointer {
  cursor: pointer;
}
</style>

在要使用的页面引入

<script setup lang="ts">
import Ellipsis from './Ellipsis.vue'
</script>
<template>
  <div>
    <h1>{
  { $route.name }} {
  { $route.meta.title }}</h1>
    <h2 class="mt30 mb10">基本使用</h2>
    <Ellipsis :maxWidth="240">住在我心里孤独的 孤独的海怪 痛苦之王 开始厌倦 深海的光 停滞的海浪</Ellipsis>
    <h2 class="mt30 mb10">多行省略</h2>
    <Ellipsis :line="2">
      电灯熄灭 物换星移 泥牛入海
      <br />
      黑暗好像 一颗巨石 按在胸口
      <br />
      独脚大盗 百万富翁 摸爬滚打
      <br />
      黑暗好像 一颗巨石 按在胸口
    </Ellipsis>
    <h2 class="mt30 mb10">点击展开</h2>
    <Ellipsis expand :line="2">
      电灯熄灭 物换星移 泥牛入海
      <br />
      黑暗好像 一颗巨石 按在胸口
      <br />
      独脚大盗 百万富翁 摸爬滚打
      <br />
      黑暗好像 一颗巨石 按在胸口
    </Ellipsis>
    <h2 class="mt30 mb10">定制 Tooltip 内容</h2>
    <Ellipsis :max-width="240">
      住在我心里孤独的 孤独的海怪 痛苦之王 开始厌倦 深海的光 停滞的海浪
      <template #tooltip>
        <div style="text-align: center">
          《秦皇岛》
          <br />
          住在我心里孤独的
          <br />
          孤独的海怪 痛苦之王
          <br />
          开始厌倦 深海的光 停滞的海浪
        </div>
      </template>
    </Ellipsis>
    <h2 class="mt30 mb10">自定义 Tooltip 样式</h2>
    <Ellipsis
      :max-width="240"
      :tooltip-props="{
        bgColor: '#4096ff',
        tooltipStyle: {
          padding: '12px 16px',
          borderRadius: '12px',
          fontSize: '16px',
          backgroundColor: '#4096ff'
        }
      }"
    >
      住在我心里孤独的 孤独的海怪 痛苦之王 开始厌倦 深海的光 停滞的海浪
    </Ellipsis>
  </div>
</template>
相关文章
|
9天前
|
JavaScript API
Vue3中的计算属性能否动态修改
【9月更文挑战第5天】Vue3中的计算属性能否动态修改
40 10
|
2天前
|
JavaScript
Vue3中路由跳转的语法
Vue3中路由跳转的语法
105 58
|
5天前
|
前端开发
vue3+ts项目中使用mockjs
vue3+ts项目中使用mockjs
198 58
|
2天前
|
JavaScript 开发工具
vite如何打包vue3插件为JSSDK
【9月更文挑战第10天】以下是使用 Vite 打包 Vue 3 插件为 JS SDK 的步骤:首先通过 `npm init vite-plugin-sdk --template vue` 创建 Vue 3 项目并进入项目目录 `cd vite-plugin-sdk`。接着,在 `src` 目录下创建插件文件(如 `myPlugin.js`),并在 `main.js` 中引入和使用该插件。然后,修改 `vite.config.js` 文件以配置打包选项。最后,运行 `npm run build` 进行打包,生成的 `my-plugin-sdk.js` 即为 JS SDK,可在其他项目中引入使用。
|
3天前
|
JavaScript 开发者
彻底搞懂 Vue3 中 watch 和 watchEffect是用法
彻底搞懂 Vue3 中 watch 和 watchEffect是用法
|
9天前
|
JavaScript API
如何使用Vue3的可计算属性
【9月更文挑战第5天】如何使用Vue3的可计算属性
42 13
vue3 reactive数据更新,视图不更新问题
vue3 reactive数据更新,视图不更新问题
|
9天前
|
资源调度 JavaScript API
vue3 组件通信方式
vue3 组件通信方式
39 11
|
1天前
|
JavaScript
|
1天前
vue3定义暴露一些常量
vue3定义暴露一些常量