• 技术文章 >微信小程序 >小程序开发

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

    青灯夜游青灯夜游2022-03-07 19:46:05转载1615
    小程序怎么实现“全文收起”功能?下面本篇文章小程序实现多行文本“全文收起”功能的方法,希望对大家有所帮助!

    小程序里经常会碰到需要实现多行文本”全文收起“功能,在掘金上有搜索到用纯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.png

    三、代码实现

    1、初次版本

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

    foldable.wxml

    <view class="content">
      <view class="contentInner content-inner-class showArea {{!onFold ? 'text-clamp' + maxLine : ''}}">{{content}}</view>
      <view class="contentInner content-inner-class hideArea" style="width: {{width}}px">{{content}}</view>
      <view class="foldInner fold-class {{position === 'right' ? 'flex-end' : 'flex'}}" 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: ['content-inner-class', 'fold-class'],
      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()计算的高度会有存在是实际高低的两倍的现象。导致会错误出现【全文】文字。然后文本从两行增加到三行或者多行都没问题,不太理解为什么会出现这个错误计算的现象。(期待大神能留言告知 ? )

    2.png

    为了弥补这个坑,我引入了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、最终版本

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

    3.png

    4.png

    通过分析代码可知,在展开全文的状态下更新了文本,此时.showArea节点和.hideArea节点的高度一致,执行代码let showFold = res[0].height < 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/GWj19vmC7oxp

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

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

    以上就是聊聊小程序怎么实现“全文收起”功能的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:掘金社区,如有侵犯,请联系admin@php.cn删除
    专题推荐:小程序 全文收起
    上一篇:零基础微信小程序开发及实例详解 下一篇:微信小程序开发底部导航
    VIP课程(WEB全栈开发)

    相关文章推荐

    • 【活动】充值PHP中文网VIP即送云服务器• 小程序与公众号开发的区别是什么• 手把手教你在微信小程序中使用canvas绘制天气折线图(附代码)• 浅析小程序中什么是behaviors?怎么创建和使用?• 总结分享微信小程序的开发步骤• 零基础微信小程序开发及实例详解
    1/1

    PHP中文网