vue两行文本溢出显示展开按钮

微信小程序
现在有一个需求,当文本超过两行溢出显示省略号,并在末尾展示展开按钮
我现在的做法是动态绑定class类名,当他的字符长度超过45的时候就

if (item.reply && item.reply.length < 45) item.replyFlag = true
 // reply字段就是返回的文字

这是正常显示

img

当输入的数字就会这样这里的长度都还没到45

img

当输入的英文长度==45的时候就会这样

img

    width: 94%;
    display: -webkit-box;
    overflow: hidden;
    text-overflow: ellipsis;
    word-wrap: break-word;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
// 这是长度不超过45的样式
// 超过45的时候
// -webkit-line-clamp:inherit

请问这种怎么解决或者还有别的更好的方式处理吗

小程序组件封装
设置行高,2行多高换算成px,这里组件是5行换算成px是126,渲染后获取元素高度判断是否超出,超出增加对应样式和控制显示展开按钮
wx.js

import random from 'lodash.random';

Component({
  options: { addGlobalClass: true },
  properties: {
    text: String,
  },

  data: {
    showExpande: false,
    ellipsis: false,
    id: '',
  },

  lifetimes: {
    ready() {
      if (this.data.text) {
        this.init();
      }
    },
  },

  methods: {
    onToggle() {
      this.setData({ ellipsis: !this.data.ellipsis });
    },

    init() {
      this.setData({ id: 'content' + Date.now() + random(100000, 999999).toString() }, () => {
        const query = wx.createSelectorQuery().in(this);
        query.select(`#${this.data.id}`).boundingClientRect((res) => {
          const showExpande = res?.height > 126;
          this.setData({ showExpande });
        }).exec();
      });
    },
  },
});

wx.wxml

<view wx:if="{{text}}" class="act-detail_intro border-box pd-20 mt-40 radius-24 flex-column">
    <view class="font-28 {{!ellipsis ? 'ellipsis-5' : ''}}">
        <text id="{{id}}" decode space>{{text}}</text>
    </view>
    <view class="fold_btn width-full flex-end font-28" bindtap="onToggle" wx:if="{{showExpande}}">{{!ellipsis ? '展开' : '收起'}}</view>
</view>

wx.wxss

.act-detail_intro {
  background: rgba(255, 255, 255, 0.2);
  font-weight: 400;
  color: #ffffff;
  line-height: 42rpx;
}

.act-detail_intro .fold_btn {
  font-weight: 400;
  line-height: 42rpx;
  color: rgba(255, 255, 255, 0.2);
}
.ellipsis-5 {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  text-overflow: -o-ellipsis-lastline;
  overflow: hidden;
  text-overflow: ellipsis;
  -webkit-line-clamp: 5;
  line-clamp: 5;
}

wx.json

{
  "component": true,
  "usingComponents": {}
}

replyFlag定义三个值,0、1、2分别代表不显示,展开状态,收起状态
然后你再根据字数赋值

因为你设置的字符长度,一个英文单词就是一个字符,推荐一种写法,把溢出省略单独写到一个css样式里面,然后判断这个文本的高度,超过某个界限的时候添加溢出省略的css样式,并添加一个展开,收起的按钮

现在是判断字符长度,换成判断元素高度,超过两行的高度就给它折叠显示...

应该没有 太好的 方法了 。用css 控制就行 。判读字符 长度

css 里加上这个属性:

word-break: break-all;

建议选择用css控制超出两行省略显示,根据高度变化判断是否显示展开收起按钮

1、计算实际行高。createElement div插入文字,一行文字的时候行高是多少,然后乘2,计算最大行高。

img

img

2、判断当前实际文字的行高是多少,未超过上个步骤中最大行高则直接将内容返回显示。

img

3、如果超过了最大行高,那么需要写个递归算法,对文字不断截取插入,看行高是否超过最大行高,直到找到最合适的文字长度。

img

4、点击更多增将原来的完整的文字插入。

因为写起来太费劲,所以未完整实现。我实际参考ant-design-vue typography组件实现方式分解的步骤,你可以去看看它的源码。

定义内容占位盒子A溢出ellipsis,内容B宽度能自动auto,收起展开按钮C会跟着内容auto变化往右挤:
1.当C被B挤出来超出A的宽度了就可见;
2.当C被B挤出来没能超出A的宽度了就不可见,类似于C被A遮盖住了一样
3.收起展开按钮切换控制切换一下A的高度auto

用这种思想来实现足够了

为什么要判断字符长度呢,不是说的是两行蒙,不同屏幕大小不一样啊,可输入字符长度也不一样,所以直接判断div超出就显示

实现方案一: 采用js的方式,首先判断元素是否超过了两行,超过的话截取前N个字符拼接上省略号 ... 展示;不超过两行正常展示。判断元素内容是否超过 n 行的方法如下:

/**
 * 工具方法参数类型
 */
export interface MoreThanLineParams {
  containerClassName: string; // 父元素类名,需包含字号属性
  width: number; // 行宽度
  content: string; // 内容
  line?: number; // 行数
}
/**
 * 判断元素是否超过n行
 * 默认两行
 */
export const moreThanLines = ({
  containerClassName,
  content,
  width,
  line = 2,
}: MoreThanLineParams) => {
  let result = false;
  // 用于存放内容的元素
  const tempNode = document.createElement('div');
  tempNode.setAttribute('id', 'temp-node');
  tempNode.style.position = 'absolute';
  tempNode.style.visibility = 'hidden';
  // 将传递进来的类名和文本内容赋值
  tempNode.classList.add(containerClassName);
  tempNode.style.width = width + 'px';
  tempNode.innerHTML = content;
  const containerNode = document.body.appendChild(tempNode);
  // 用于计算行高的元素
  const dupNode = document.createElement('div');
  dupNode.classList.add(containerClassName);
  dupNode.style.width = width + 'px';
  dupNode.style.wordBreak = 'keep-all';
  dupNode.style.overflowWrap = 'normal';
  dupNode.style.whiteSpace = 'nowrap';
  dupNode.style.position = 'absolute';
  dupNode.innerHTML = content.substring(0, 2);
  dupNode.setAttribute('id', 'copy-node');
  const getLineHeightNode = document.body.appendChild(dupNode);

  if (containerNode.offsetHeight > getLineHeightNode.offsetHeight * line) {
    result = true;
  }
  document.body.removeChild(containerNode);
  document.body.removeChild(getLineHeightNode);
  return result;
};


【CSS 文字截断技巧】https://zhuanlan.zhihu.com/p/35713421
【CSS 实现多行文本展开收起效果】https://github.com/sisterAn/blog/issues/120