谈谈小程序如何实现“全文收起”功能-小程序开发

首页 2024-07-09 07:59:58

小程序如何实现“全文折叠”功能?下面这篇文章的小程序实现了多行文本“全文折叠”功能的方法,希望对大家有所帮助!

在小程序中,经常会遇到需要实现多行文本的全文收起“功能”实现纯css。亲测:ios很完美,andriod上的无效

小程序社区有很多方案。目前,我看到一个大人物在社区里使用它动态计算js告诉实现,亲测大致有效。测试结束后,在某些特殊情况下,计算会出现误差,因此会更改一些代码。

一、需求
  • 全文/收起“按钮”位于多行文本右下角
  • “展开”和“收起”之间的切换
  • 当文本不超过指定行数时,不显示“全文/收起”按钮
  • 在文本显示[全文]显示状态下,更新数据,文本不会被收起
二、实现思路 1、多行文本截断

主要用于使用?line-clamp,关键样式如下

.text-clamp3 {
  overflow: hidden;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
}
2、判断文本是否超过指定行数,显示全文 收起 按钮

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

wx可用于小程序.createSelectorQuery()获取文本高度

js

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

三、实现代码1、初次版本

根据设计思路,立即启动代码

foldable.wxml

<view class="content">
  <view class="contentInner content-inner-class showArea {{!onFold ? &#39;text-clamp&#39;   maxLine : &#39;&#39;}}">{{content}}</view>
  <view class="contentInner content-inner-class hideArea" style="width: {{width}}px">{{content}}</view>
  <view class="foldInner fold-class {{position === &#39;right&#39; ? &#39;flex-end&#39; : &#39;flex&#39;}}" wx:if="{{showFold}}">
    <text class="fold" catchtap="handleFold">{{onFold ? unFoldText : onFoldText}}</text>
  </view>
</view>

foldable.js

/**
 * 展开和收起长文本内容
 * @param {String} content  长文本内容
 * @param {Number} maxLine  最多显示行数[只允许 1-5 的正整数]
 * @param {String} position  展开收起按钮位置[可选值为 left right]
 * @param {Boolean} foldable  点击长文本是否展开收集
 * @param { String } onFoldText 收缩时文字
 * @param { String } unFoldText 展开时文字
 * 
 */

Component({
  externalClasses: [&#39;content-inner-class&#39;, &#39;fold-class&#39;],
  properties: {
    content: {
      type: String,
      observer(val) {
        if (this.data.onReady) {
          this.getNodeClientReact()
        }
      }
    },
    maxLine: {
      type: Number,
      value: 1,
      observer(value) {
        if (!(/^[1-5]$/).test(value)) {
          throw new Error(`maxLine field value can only be digits (1-5), Error value: ${value}`)
        } else if (this.data.onReady) {
          this.getNodeClientReact()
        }
      }
    },
    position: {
      type: String,
      value: "left"
    },
    foldable: {
      type: Boolean,
      value: true
    },
    // 收缩时文字
    onFoldText: {
      type: String,
      value: "全文"
    },
    // 展开时文字
    unFoldText: {
      type: String,
      value: "收起"
    },
  },
  data: {
    width: null,
    onFold: false,
    showFold: false,
    onReady: false
  },
  lifetimes: {
    attached() {
      this.getNodeClientReact()
      this.setData({
        onReady: true
      })
    },
  },
  methods: {
    getNodeClientReact() {
      setTimeout(() => this.checkFold(), 10)
    },
    checkFold() {
      const query = this.createSelectorQuery();
      query.selectAll(".showArea, .hideArea").boundingClientRect(res => {
        let showFold = res[0].height < res[1].height;
        this.setData({
          width: res[0].width,
          showFold,
        })
      }).exec()
    },
    handleFold() {
      this.setData({
        onFold: !this.data.onFold
      })
    }
  }
})

foldable.wxss

.content {
  width: 100%;
  position: relative;
  overflow: hidden;
}

.contentInner {
  word-break: break-all;
  width: 100%;
  color: #2f3033;
  font-size: 30rpx;
  line-height: 1.35;
}

.hideArea {
  display: -webkit-box;
  overflow: hidden;
  position: fixed;
  top: 100vh;
  left: -100vw;
}

.foldInner {
  padding-top: 10rpx;
  color: #6676bd;
  font-size: 32rpx;
}

.foldInner .fold {
  cursor: pointer;
}

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

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

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

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

.text-clamp5 {
  overflow: hidden;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 5;
}
2、修复版本

在正常情况下,这种方法是可行的,但在等级文本下,会计是错误的。测试后,可以 节点是.hidearea的内容定位在.showarea节点可以解决

foldable.wxss

.hideArea {
  display: -webkit-box;
  overflow: hidden;
  /* position: fixed;
  top: 100vh;
  left: -100vw; */
  position: absolute;
  top: 0;
  left: 0;
  z-index: -1;
  color: #fff;
}
3、增强版本

修复后,本可以完美实现,但在测试过程中,第一次正常渲染没有问题。但是,如果文本数据更新,则会发现如果原始文本从一行增加到两行,则使用wx.createSelectorQuery()计算高度是实际高度的两倍。【全文】文字会出现错误。然后文本从两行增加到三行或多行没有问题。我不明白为什么会出现这种错误的计算。(期待大神能留言通知 ? )

为了弥补这个坑,我介绍了lineHieght的属性。

// foldable.js
Component({
    properties: {
        lineHieght: {
          type: Number,
          observer(value) {
            if (!(/^[0-9]*$/).test(value)) {
              throw new Error(`lineHieght field value can only be digits`)
            }
          }
        }
    }
})

最大高度可以通过lineHieght和最多可以显示的行数maxLine来计算。

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

当然,通过wx,我们也需要适应不同的设备.createSelectorQuery()计算结果以px为单位。

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

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

因此,更新checkFold方法

checkFold() {
  const query = this.createSelectorQuery();
  query.selectAll(".showArea, .hideArea").boundingClientRect(res => {
    let showFold = res[0].height < res[1].height;
    const lineHeightToPx = this.changeRpxToPx(this.data.LineHeight);
    // 显示区域高度(即可能被截取的可见文本)
    const showAreaHeight = res[0].height;
    // 隐藏区域的高度(即完整文本的高度),意外事件会计算错误)
    const hideAreaHeight = res[1].height;
    // 文本可见的最大高度
    const maxHeight = lineHeightToPx * this.data.maxLine;
    // 若是一行文字,偶然计算错误,用行高判断
    if (this.data.LineHeight && showAreaHeight <= maxHeight) {
      showFold = hideAreaHeight > maxHeight
    }
    this.setData({
      width: res[0].width,
      showFold,
    })
  }).exec()
},
4、最终版本

在上一个版本之后,基本功能已经实现。但是,如果文本超过最大行数,并且文本在全文展开时更新,则全文/展开按钮将显示错误。

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

因此,解决方案如下:

// 如果文本超过最大行数并显示全文,文字再次更新
let onFold = false
if (showAreaHeight == hideAreaHeight && showAreaHeight > maxHeight) {
  showFold = true
  onFold = true
}

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

checkFold() {
  const query = this.createSelectorQuery();
  query.selectAll(".showArea, .hideArea").boundingClientRect(res => {
    let showFold = res[0].height < res[1].height;
    const lineHeightToPx = this.changeRpxToPx(this.data.LineHeight);
    // 显示区域高度(即可能被截取的可见文本)
    const showAreaHeight = res[0].height;
    // 隐藏区域的高度(即完整文本的高度),意外事件会计算错误)
    const hideAreaHeight = res[1].height;
    // 文本可见的最大高度
    const maxHeight = lineHeightToPx * this.data.maxLine;
    // 若是一行文字,偶然计算错误,用行高判断
    if (this.data.LineHeight && showAreaHeight <= maxHeight) {
      showFold = hideAreaHeight > maxHeight
    }
    // 若文本超过最大行数,并且显示全文状态,文字再次更新
    let onFold = false
    if (showAreaHeight == hideAreaHeight && showAreaHeight > maxHeight) {
      showFold = true
      onFold = true
    }
    this.setData({
      width: res[0].width,
      showFold,
      onFold,
    })
  }).exec()
},
四、代码片段
经过多次测试和修改,最后附上代码片段:https://developers.weixin.qq.com/s如果大神有更好的建议,可以留言~~~

【相关学习推荐:小程序开发教程】

以上就是关于小程序如何实现“全文收起”功能的详细内容,更多请关注其它相关文章!


p