多行省略的实现

多行省略的实现

在实际开发中,经常会遇到当文本内容比较多时,由于显示区域空间的限制,我们只需显示一部分内容,剩余的内容则用省略号(…)代替。

单行省略:

关于单行多余内容省略的实现,可以简单的通过css样式来实现:

.ellipsis{
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
多行省略(css版):

如果不考虑浏览器的兼容性,多行省略的实现,也可以通过css样式实现:

.ellipsis{
	overflow: hidden;
	text-overflow: ellipsis;
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 3;
}

通过修改-webkit-line-clamp值就可以实现多行省略效果,该实现方式最大的问题就是浏览器兼容性问题,在chrome下可以达到想要的效果,在IE下则不生效;

多行省略(js版):

那么关于多行省略,有没有一个兼容性比较好的实现方案?

本文提供一种利用js实现的方案,并将其抽离为一个vue指令以方便使用。

demo效果:

在这里插入图片描述

原理:

获取显示文本text超出限定行数时的字符对应的索引,根据索引对text进行截取并拼接‘…’替换原内容。

如下图所示,是一段内容很长的文本,现在想实现两行省略,超出两行的文字需要省略并用...代替,首先要做的就是找到第三行第一个字符对应的索引,也就是"路"这个字对应的索引,根据该索引值对文本内容进行截取并拼接...,最终替换原文本内容。
在这里插入图片描述

实现流程:

其中比较关键的是如何查找到超出限定行数的字符所对应的的索引,本文中我们通过新建一个新的div,按照文本原来现实样式在新建div中逐字显示文本内容,在显示过程中,实时获取新建div的高度,并将其与限定行数的高度进行比较,当新建div的高度大于限定高度时,获取当前字符对应的索引。具体实现流程如下:
在这里插入图片描述

1、在vue指令中,我们使用钩子函数,就很容易获取到使用指令的DOM元素,然后将文本内容保存;

2、根据限定行数以及文本渲染时的行高,可以计算出文本内容所在标签的限制高度,并对超出的内容设置隐藏;

3、新建一个div,并将文本内容所在标签的一些关键样式(宽度、行高、字体大小)设置到新的div,以方便在新的div中按照相同方式渲染文本,然后遍历文本内容,逐字添加到新的div中,并实时获取div高度,将其与限制高度进行比较,得到超出限定行数时字符对应的索引;

代码实现:

将上述过程转换为代码如下:

// ellipsis.js
function setEllipsis(el, binding, vnode) {
  // 接收指令传参(行数、字体大小、右侧留白数)
  const lineNum = binding.value.line || 1;
  const rightBlankNum = binding.value.rightBlank || 0;
  const showTitle = binding.value.showTitle || false;
  
  // 获取显示的文本内容
  const text = el.innerHTML;
  if (!text.length) return;
  if (showTitle) el.setAttribute('title', text);

  // 获取文本的行高
  const computedStyle = window.getComputedStyle(el, null);
  const textLineHeight = computedStyle.getPropertyValue('line-height');
  const textFontSize = computedStyle.getPropertyValue('font-size');

  // 设置文本超出指定行数后隐藏样式
  const limitHeight = parseInt(textLineHeight) * lineNum;
  if (limitHeight) {
    el.style.height = `${limitHeight}px`;
    el.style.overflow = 'hidden';
  }
  // 设置省略号,通过创建一个div按照同样的样式逐个字符显示文本内容,获取到达指定行数时的字符下标
  const newDiv = document.createElement('div');
  newDiv.style.width = `${el.clientWidth}px`;
  newDiv.style.lineHeight = textLineHeight;
  newDiv.style.fontSize = textFontSize;
  newDiv.style.visibility = 'hidden';
  document.body.appendChild(newDiv);
  let targetIndex;
  for (let i = 0, len = text.length; i < len; i++) {
    newDiv.innerHTML = text.substring(0, i);
    if (newDiv.clientHeight > limitHeight) {
      targetIndex = i;
      break;
    }
  }
  document.body.removeChild(newDiv);
  el.innerHTML = targetIndex ? `${text.substring(0, targetIndex - rightBlankNum - 3)}...` : text;
  el.setAttribute('data-overflow', !!targetIndex);
}

export default {
  inserted(el, binding, vnode) {
    setEllipsis(el, binding, vnode);
  },
};

由于采用vue指令方式实现多行省略效果,为了方便注册该指令,我们提供了一个install方法,方便在项目中使用Vue.use()进行全局注册

// index.js
// 将多行省略指令代码引入
import ellipsis from './ellipsis.js';

// 暴露install方法,install方法内为执行指令注册
export default {
  install(Vue) {
    Vue.directive('ellipsis', ellipsis);
  },
};
指令使用方法:

指令书写完后,最重要的是如何在实际项目方便使用,如下:

我们将指令的源码ellipsis.js和index.js文件放在multilineEllipsis文件夹中,使用时将源码拷贝到项目中,然后在项目的main.js中调用Vue.use()全局注册该指令,如下:

// 引入ellipsis
import ellipsis from '../../multilineEllipsis/index'

// 全局注册
Vue.use(ellipsis)

全局注册成功后,我们就可以随意在项目中使用该指令:

注意:使用v-ellipsis指令时,要确保文本的行高为像素值,而非normal、百分比、数值。

v-ellipsis指令接收3个参数:

参数说明类型
line行数,设置需要显示省略号时的行数number
showTitle是否显示title,文本超出显示省略时,当鼠标hover上去时是否在title上显示完整的内容boolean
rightBlank默认省略号显示在指定行数的末尾,如果需要将省略号距离末尾留有一定空白,可设置该参数number

实现细节:

1、vue自定义指令为我们提供了多个钩子函数(bind、inserted、update、componentUpdated、unbind),对于多行省略指令,我们选择了使用inserted钩子函数,是因为我们希望省略处理的操作都能够在文本内容加载完成后进行。

2、vue中,在自定义指令的钩子函数中,我们可以获取到使用指令标签的DOM元素,但在获取文本行高、字体大小时,我们使用window.getComputedStyle(el, null).getPropertyValue('line-height')方式获取而非el.style.lineHeight获取,是因为el.style.lineHeight获取到行高的前提是我们需要在标签上通过style属性添加line-height属性,但在实际开发中,我们可能会继承父级标签的行高或通过class设置行高,就会导致el.style.lineHeight值为空。而getComputedStyle获取的是元素计算之后的样式,不管line-height设置方式如何,都可以获取到值。

3、在通过新建div元素进行一比一还原文本内容显示时,需要将使用指令的标签元素的宽度、行高、字体大小样式都应用到新的div上,这样就保证了文本内容新建div中所占据的空间与在指令标签中一样。

最后,完整的代码以及demo可以在github中查看

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值