聊聊小程序怎么实现“全文收起”功能
小程序怎么实现“全文收起”功能?下面本篇文章小程序实现多行文本“全文收起”功能的方法,希望对大家有所帮助!
小程序里经常会碰到需要实现多行文本”全文收起“功能,在掘金上有搜索到用纯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 ? '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()
计算的高度会有存在是实际高低的两倍的现象。导致会错误出现【全文】
文字。然后文本从两行增加到三行或者多行都没问题,不太理解为什么会出现这个错误计算的现象。(期待大神能留言告知 ? )
为了弥补这个坑,我引入了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
,因此按钮会消失。
因此解决方案为:
- // 如果文本超出最大行数,并且是显示全文的状态下,再次更新了文字
- 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
各位大神如果有更好的建议,可留言哦~~~
本文网址:https://www.zztuku.com/detail-11214.html
站长图库 - 聊聊小程序怎么实现“全文收起”功能
申明:本文转载于《掘金社区》,如有侵犯,请 联系我们 删除。
您还没有登录,请 登录 后发表评论!
提示:请勿发布广告垃圾评论,否则封号处理!!