小程序技巧系列——多行文本溢出省略,超出显示展开按钮

4,860 阅读4分钟

本文仅针对在小程序侧的多行文本溢出省略,超出现实展开按钮的实现。web方向的实现,不在本文赘述。

效果

  • 两种方式
    • 一种是另起一行的
    • 一种是在省略号右侧

另起一行展示”展开收起“

要点:

  • 多行省略,并且不超过制定行数时,不显示展开按钮
  • 如何判断是否已超出省略

多行文本省略

这块比较简单,css已实现多行文本省略的属性,在小程序侧可以直接使用。并且该属性可以让文字在不超过制定行数时,不显示展开按钮。

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

通过上面的代码,我们就可以实现多行文本的yichu省略啦。接下来我们来实现显示展开按钮

显示展开按钮

是否显示展开按钮,核心就是如何判断当前文本是否已超出溢出。由于溢出省略这块的逻辑全部都由CSS实现,不可以直接通过样式来拿到当前是否溢出的状态。因此我们想到是否可以通过js来做判断。

首先我们想到的是,当视图在页面中渲染完成,这个时候我们是可以拿到相关元素的位置及宽高信息的,那如何通过这种信息来识别是否溢出隐藏呢。

其实我们可以在通过多展示一个不溢出隐藏的容器,来承载这些文字,只是将该容器进行隐藏而且不影响当前视图布局。可以使用多展示的容器通过绝对定位超出当前文档流。

样式布局

<view class="content-wrap">
  <view class="content">
    文本内容
  	<view class="content-hide">文本内容</view>
  </view>
</view>

对应的CSS。

.content {
  position: relative;
   overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
}
.content-hide {
   position: absolute;
   left: 0;
   top: 0;
   z-index: -1;
   visibility: hidden;
}

JS逻辑操作

这里考虑前端静态数据的情况下,如果是根据后端返回数据的渲染,可以在对应的setData之后的回调中进行计算。这里考虑只有一条数据时的情况

Page({
  data: {
  	overflowStatus: false,
  }

	onReady(){
  	this.calcOverflowStatus();
  },
  calcOverflowStatus() {
    const query = this.createSelectorQuery();
    query.select('.content').boundingClientRect();
    query.select('.content-hide').boundingClientRect();
    query.exec((res) => {
    	this.setData({
      	overflowStatus: res[1].height - res[0].height
      })
    })
  	
  }
})

这样我就实现了另起一行展示”展开收起“按钮的操作了

右下角展示“展开收起”

这里是参考阅文前端团队的文章CSS 实现多行文本“展开收起”,在小程序侧的实现。

注意的点:

  • 当display设置为-webkit-box时,该容器内的float元素不生效,因此这里直接使用其提供的兼容写法,就不能使用line-clamp属性了。
  • 当我们设置容器的before伪元素的位置时,偏移量的单位使用px,否则使用rpx在各个机型上进行动态计算,会导致有误差。
  • 动态高度的问题,在不定高的情况下,如何使height:100%生效。这里可以使用flex布局,因为flex布局的子项中,可以通过百分比来计算变化高度。

html结构

	<view class="wrap">
		<view class="content-box {{open ? 'open' : ''}} ">
			<view wx:if="{{!open && overflowStatus}}" class="more-btn" bindtap="handleOpen">展开</view>
			{{content}}
		</view>
	</view>

wrap最外层的容器,主要是为了解决height: 100%失效的问题。给该元素设定display: flex属性。

.wrap {
  display: flex;
}

多行文本省略

这里直接写兼容写法。

.content {
  /*
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  */
  line-height: 1.5;
  max-height: 4.5em;
  overflow: hidden;
  text-align: justify;
}

这里使用text-align: justify来实现...与文字对齐。否则的话会出现,展示省略号的一行,省略号无法与文字紧挨在一起。

展示“展开”按钮

这里参考阅文团队的大佬,使用float元素来实现。直接展示完整的css代码。

.wrap {
  display: flex;
}
.content-box {
   overflow: hidden;
    line-height: 1.5;
    max-height: 4.5em;
    text-align: justify;
    color: #999;
    position: relative;
}
.content-box.open {
  max-height: none;
}
.content-box::before {
  content: '';
  float: right;
  height: 100%;
  width: 0;
  margin-bottom: -24px;
  /* height: calc(100% - 24px);  */
}
.more-btn {
  color: #000;
  float: right;
  clear: both;
  position: relative;
}
.more-btn::before{
    content: '...';
    color: #999;
    font-size: 14px;
    margin-right: 8rpx;
}

解读:

  • 最外层的wrap容器设定display解决context-box的伪元素设定height:100%失效的问题
  • 利用context-box的伪元素右浮动,并设定其高度为100%。more-btn设定float: right时,这时会看到是展示在context-box伪元素的左侧,如何将其放到下面呢。可以让more-btn清除下浮动clear: both; 这样就是实现了展开按钮右下角环绕效果了。
  • 但是content-box的伪元素高度设定为100%,则会导致将more-btn直接被挤出容器,因此可以设定content-box的伪元素一个margin-bottom负值,这样可以让more-btn展示出来。
  • 这里margin-bottom设定为-24px,而不是小程序的rpx单位,是由于rpx还会在各个机型上进行计算,导致位置出现误差,这里直接使用px单位,保证位置准确性
  • 省略号的添加,利用more-btn元素的伪元素来添加。

超过设定的行数展开按钮展示

这里依然使用JS判断的手段。跟另起一行展示的手法保持一致。

Page({
  data: {
  	overflowStatus: false,
  }

	onReady(){
  	this.calcOverflowStatus();
  },
  calcOverflowStatus() {
    const query = this.createSelectorQuery();
    query.select('.content-box').boundingClientRect();
    query.select('.content-hide').boundingClientRect();
    query.exec((res) => {
    	this.setData({
      	overflowStatus: res[1].height - res[0].height
      })
    })
  	
  }
})

参考

juejin.cn/post/696390…