聊聊小程序怎么实现“全文收起”功能

 3996

小程序怎么实现“全文收起”功能?下面本篇文章小程序实现多行文本“全文收起”功能的方法,希望对大家有所帮助!


聊聊小程序怎么实现“全文收起”功能


小程序里经常会碰到需要实现多行文本”全文收起“功能,在掘金上有搜索到用纯css实现。亲测:ios很完美,andriod上的无效

小程序社区有很多方案,目前在社区有看到一位大佬使用js动态计算告诉去实现,亲测大致有效果,测试后,在一些特殊情况下,计算会有误差,所以有更改些许代码。

一、需求

位于多行文本右下角,展示”全文/收起“按钮

“展开”和“收起”两种状态的切换

当文本不超过指定行数时,不显示”全文/收起“按钮

文本显示【全文】展示状态下,更新数据,文本不被收起

二、实现思路

1、多行文本截断

主要用到用到 line-clamp,关键样式如下

  1. .text-clamp3 {
  2.   overflow: hidden;
  3.   display: -webkit-box;
  4.   -webkit-box-orient: vertical;
  5.   -webkit-line-clamp: 3;
  6. }

2、判断文本是否超出指定行数,显示全文 收起 按钮

编写两段文本,一段展示完整的文本A,一段展示使用 line-clamp省略后的文本B,因为B有被截取,因此B的高度相对较小。对比两段文本的高度,便可以知道文本是否超出两行

在小程序里,可以使用wx.createSelectorQuery()获取文本高度

js

  1. const query = wx.createSelectorQuery().in(this);
  2. query.selectAll(".showArea, .hideArea").boundingClientRect(res => {
  3.     console.log(res, 'res')
  4. }).exec()


聊聊小程序怎么实现“全文收起”功能


三、代码实现

1、初次版本

根据设计思路,立马上手代码

foldable.wxml

  1. <view class="content">
  2.   <view class="contentInner content-inner-class showArea {{!onFold ? 'text-clamp' + maxLine : ''}}">{{content}}</view>
  3.   <view class="contentInner content-inner-class hideArea" style="width: {{width}}px">{{content}}</view>
  4.   <view class="foldInner fold-class {{position === 'right' ? 'flex-end' : 'flex'}}" wx:if="{{showFold}}">
  5.     <text class="fold" catchtap="handleFold">{{onFold ? unFoldText : onFoldText}}</text>
  6.   </view>
  7. </view>

foldable.js

  1. /**
  2.  * 长文本内容展开与收起
  3.  * @param {String} content  长文本内容
  4.  * @param {Number} maxLine  最多展示行数[只允许 1-5 的正整数]
  5.  * @param {String} position  展开收起按钮位置[可选值为 left right]
  6.  * @param {Boolean} foldable  点击长文本是否展开收起
  7.  * @param { String } onFoldText 收缩时文字
  8.  * @param { String } unFoldText 展开时文字
  9.  * 
  10.  */
  11.  
  12. Component({
  13.   externalClasses: ['content-inner-class', 'fold-class'],
  14.   properties: {
  15.     content: {
  16.       type: String,
  17.       observer(val) {
  18.         if (this.data.onReady) {
  19.           this.getNodeClientReact()
  20.         }
  21.       }
  22.     },
  23.     maxLine: {
  24.       type: Number,
  25.       value: 1,
  26.       observer(value) {
  27.         if (!(/^[1-5]$/).test(value)) {
  28.           throw new Error(`maxLine field value can only be digits (1-5), Error value: ${value}`)
  29.         } else if (this.data.onReady) {
  30.           this.getNodeClientReact()
  31.         }
  32.       }
  33.     },
  34.     position: {
  35.       type: String,
  36.       value: "left"
  37.     },
  38.     foldable: {
  39.       type: Boolean,
  40.       value: true
  41.     },
  42.     // 收缩时文字
  43.     onFoldText: {
  44.       type: String,
  45.       value: "全文"
  46.     },
  47.     // 展开时文字
  48.     unFoldText: {
  49.       type: String,
  50.       value: "收起"
  51.     },
  52.   },
  53.   data: {
  54.     width: null,
  55.     onFold: false,
  56.     showFold: false,
  57.     onReady: false
  58.   },
  59.   lifetimes: {
  60.     attached() {
  61.       this.getNodeClientReact()
  62.       this.setData({
  63.         onReady: true
  64.       })
  65.     },
  66.   },
  67.   methods: {
  68.     getNodeClientReact() {
  69.       setTimeout(() => this.checkFold(), 10)
  70.     },
  71.     checkFold() {
  72.       const query = this.createSelectorQuery();
  73.       query.selectAll(".showArea, .hideArea").boundingClientRect(res => {
  74.         let showFold = res[0].height < res[1].height;
  75.         this.setData({
  76.           width: res[0].width,
  77.           showFold,
  78.         })
  79.       }).exec()
  80.     },
  81.     handleFold() {
  82.       this.setData({
  83.         onFold: !this.data.onFold
  84.       })
  85.     }
  86.   }
  87. })

foldable.wxss

  1. .content {
  2.   width: 100%;
  3.   position: relative;
  4.   overflow: hidden;
  5. }
  6.  
  7. .contentInner {
  8.   word-break: break-all;
  9.   width: 100%;
  10.   color: #2f3033;
  11.   font-size: 30rpx;
  12.   line-height: 1.35;
  13. }
  14.  
  15. .hideArea {
  16.   display: -webkit-box;
  17.   overflow: hidden;
  18.   position: fixed;
  19.   top: 100vh;
  20.   left: -100vw;
  21. }
  22.  
  23. .foldInner {
  24.   padding-top: 10rpx;
  25.   color: #6676bd;
  26.   font-size: 32rpx;
  27. }
  28.  
  29. .foldInner .fold {
  30.   cursor: pointer;
  31. }
  32.  
  33. .text-clamp1 {
  34.   overflow: hidden;
  35.   display: -webkit-box;
  36.   -webkit-box-orient: vertical;
  37.   -webkit-line-clamp: 1;
  38. }
  39.  
  40. .text-clamp2 {
  41.   overflow: hidden;
  42.   display: -webkit-box;
  43.   -webkit-box-orient: vertical;
  44.   -webkit-line-clamp: 2;
  45. }
  46.  
  47. .text-clamp3 {
  48.   overflow: hidden;
  49.   display: -webkit-box;
  50.   -webkit-box-orient: vertical;
  51.   -webkit-line-clamp: 3;
  52. }
  53.  
  54. .text-clamp4 {
  55.   overflow: hidden;
  56.   display: -webkit-box;
  57.   -webkit-box-orient: vertical;
  58.   -webkit-line-clamp: 4;
  59. }
  60.  
  61. .text-clamp5 {
  62.   overflow: hidden;
  63.   display: -webkit-box;
  64.   -webkit-box-orient: vertical;
  65.   -webkit-line-clamp: 5;
  66. }


2、修复版本

正常情况下,此方法可行,但是在级别文字下,会计算错误。经过测试,可将 节点是.hideArea的内容定位在.showArea节点下可解决

foldable.wxss

  1. .hideArea {
  2.   display: -webkit-box;
  3.   overflow: hidden;
  4.   /* position: fixed;
  5.   top: 100vh;
  6.   left: -100vw; */
  7.   position: absolute;
  8.   top: 0;
  9.   left: 0;
  10.   z-index: -1;
  11.   color: #fff;
  12. }

3、增强版本

经过修复之后,本来是可以完美实现了,但是在测试过程中,第一次正常渲染是没有问题。但如果文本数据更新,会发现如果原来的文本从一行增加到两行时,使用wx.createSelectorQuery()计算的高度会有存在是实际高低的两倍的现象。导致会错误出现【全文】文字。然后文本从两行增加到三行或者多行都没问题,不太理解为什么会出现这个错误计算的现象。(期待大神能留言告知 ? )


聊聊小程序怎么实现“全文收起”功能


为了弥补这个坑,我引入了lineHieght这个属性。

  1. // foldable.js
  2. Component({
  3.     properties: {
  4.         lineHieght: {
  5.           type: Number,
  6.           observer(value) {
  7.             if (!(/^[0-9]*$/).test(value)) {
  8.               throw new Error(`lineHieght field value can only be digits`)
  9.             }
  10.           }
  11.         }
  12.     }
  13. })

通过lineHieght和最多可展示行数maxLine可以计算出,可在界面展示的最大高度。

  1. // 文本可见的最大高度
  2. const maxHeight = this.data.lineHieght * this.data.maxLine;

当然了,我们也需要适配不同的设备,而且通过wx.createSelectorQuery()计算出来的结果是以px为单位的。

所以,行高需要根据设备尺寸去改变。因为我们是以宽度是750px尺寸为设计稿的,所以根据wx.getSystemInfoSync()可以获取设备信息,进而转换成px的尺寸。

  1. // foldable.js
  2. changeRpxToPx(rpxInteger) {
  3.   return wx.getSystemInfoSync().windowWidth / 750 * rpxInteger
  4. },

因此,更新checkFold方法

  1. checkFold() {
  2.   const query = this.createSelectorQuery();
  3.   query.selectAll(".showArea, .hideArea").boundingClientRect(res => {
  4.     let showFold = res[0].height < res[1].height;
  5.     const lineHeightToPx = this.changeRpxToPx(this.data.LineHeight);
  6.     // 展示区域高度(即是可能会被截取的可见文字)
  7.     const showAreaHeight = res[0].height;
  8.     // 隐藏区域的高度(即是完整文本高度,偶然事件会计算错误)
  9.     const hideAreaHeight = res[1].height;
  10.     // 文本可见的最大高度
  11.     const maxHeight = lineHeightToPx * this.data.maxLine;
  12.     // 如果是一行文字,偶然计算错误,用行高判断
  13.     if (this.data.LineHeight && showAreaHeight <= maxHeight) {
  14.       showFold = hideAreaHeight > maxHeight
  15.     }
  16.     this.setData({
  17.       width: res[0].width,
  18.       showFold,
  19.     })
  20.   }).exec()
  21. },

4、最终版本

经过上一个版本,基本功能都已经实现。但是,如果文本超过最大行数,并且在展开全文的情况下,更新了文本,此时,全文/展开按钮会展示错误。


聊聊小程序怎么实现“全文收起”功能
聊聊小程序怎么实现“全文收起”功能


通过分析代码可知,在展开全文的状态下更新了文本,此时.showArea节点和.hideArea节点的高度一致,执行代码let showFold = res[0].height < res[1].height;,会返回false,因此按钮会消失。

因此解决方案为:

  1. // 如果文本超出最大行数,并且是显示全文的状态下,再次更新了文字
  2. let onFold = false
  3. if (showAreaHeight == hideAreaHeight && showAreaHeight > maxHeight) {
  4.   showFold = true
  5.   onFold = true
  6. }

所以最终版本的checkFold方法是:

  1. checkFold() {
  2.   const query = this.createSelectorQuery();
  3.   query.selectAll(".showArea, .hideArea").boundingClientRect(res => {
  4.     let showFold = res[0].height < res[1].height;
  5.     const lineHeightToPx = this.changeRpxToPx(this.data.LineHeight);
  6.     // 展示区域高度(即是可能会被截取的可见文字)
  7.     const showAreaHeight = res[0].height;
  8.     // 隐藏区域的高度(即是完整文本高度,偶然事件会计算错误)
  9.     const hideAreaHeight = res[1].height;
  10.     // 文本可见的最大高度
  11.     const maxHeight = lineHeightToPx * this.data.maxLine;
  12.     // 如果是一行文字,偶然计算错误,用行高判断
  13.     if (this.data.LineHeight && showAreaHeight <= maxHeight) {
  14.       showFold = hideAreaHeight > maxHeight
  15.     }
  16.     // 如果文本超出最大行数,并且是显示全文的状态下,再次更新了文字
  17.     let onFold = false
  18.     if (showAreaHeight == hideAreaHeight && showAreaHeight > maxHeight) {
  19.       showFold = true
  20.       onFold = true
  21.     }
  22.     this.setData({
  23.       width: res[0].width,
  24.       showFold,
  25.       onFold,
  26.     })
  27.   }).exec()
  28. },

四、代码片段

经过多次测试,修改,最后附上代码片段:

https://developers.weixin.qq.com/s/GWj19vmC7oxp

各位大神如果有更好的建议,可留言哦~~~


本文网址:https://www.zztuku.com/detail-11214.html
站长图库 - 聊聊小程序怎么实现“全文收起”功能
申明:本文转载于《掘金社区》,如有侵犯,请 联系我们 删除。

评论(0)条

您还没有登录,请 登录 后发表评论!

提示:请勿发布广告垃圾评论,否则封号处理!!

    编辑推荐

    css3带头像3d下拉菜单