当前位置:   article > 正文

微信小程序实现一个文字展开收起功能_小程序 展开收缩

小程序 展开收缩

1.0 需求背景

需求很常见,就是当一行文字过多时,显示省略号,然后显示展开两个字,点击,文字完全展示开,点击收起,回到省略形式,如下图

在这里插入图片描述

2.0 需求分析

有了上图,应该能更好理解,让我们再来细致分析下思路:

  1. 一行省略号,这个没啥难度,css可以实现(至于多行,差别不大)
  2. 展开和收起,初步构想是,收起状态时是通过css控制的省略号,那展开时,我们可以移除省略号的css,这样只需要添加、移除类名即可
  3. 如何确定当前行是否有省略号?这个问题,之前想过字体大小+屏幕宽度来计算一行最多能放下多少个字,实际发现,不够准确,后面想到另外一种方案;
    通过两个盒子嵌套外面大盒子只有一行文字高度,并且溢出隐藏,内层盒子就正常显示,当内层盒子高度 > 外层盒子,那么一定有省略号,故可以确定如下结构
 <!-- 外层盒子,固定只显示一行 -->
<view class="outer" style="height: {{outerHeight}}{{outerHeight == 'auto' ? '' : 'px'}}">
 <!-- 内层盒子,正常摆放,但是要动态添加省略号类名 -->
  <view 
    class="inner {{ show ? '' : 'ellipsis' }} " 
    style="padding-right: {{ show ? '0' : paddingRight }}px;">
    {{text}}
  </view>
</view>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  1. **如何确定一行文字的高度呢?**由于考虑到组件的通用性,笔者这里想了一个办法,写一个dom,将其定位到页面看不见的地方,然后获取一下,并且这里面的字体大小由外部传入,这样就能保证,不管怎么设置都可以准确获取
    <!-- 用于获取一行高度dom -->
<view class="get-height" >
  获取一行高度的盒子
</view>
  • 1
  • 2
  • 3
  • 4

3.0 具体实现

上面列举了几个问题,以及解决思考,现在我们就来具体实现

首先,获取dom高度肯定是需要的,这里把它简单封装下

  /**
   * 获取dom信息
   * **/ 
  getHeight(selector) {
    return new Promise((resolve,reject) => {
      const query = wx.createSelectorQuery().in(this)
      query.select(selector).boundingClientRect(function(res){
        resolve(res) 
      }).exec()
    })
  },
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

剩下的,大概就是高度差的判断,决定是否有省略号,以及动态添加、移除css类名,这个过程不算复杂

其实还有一个问题,就是,当确定要显示省略号时,右边切换的dom是需要定位到当前行的末尾,同时,当前行业需要一个padding,而这个padding就是切换按钮的宽度,所以这里也有一点点逻辑

4.0 完整如下

html

<view class="intercept" style="font-size: {{fontSize}};" >
  <!-- 外层盒子,固定只显示一行 -->
    <view class="outer" style="height: {{outerHeight}}{{outerHeight == 'auto' ? '' : 'px'}}">
      <view 
        class="inner {{ show ? '' : 'ellipsis' }} " 
        style="padding-right: {{ show ? '0' : paddingRight }}px;">
        {{text}}
      </view>
    </view>
    <view 
      wx:if="{{ heightInfo.realHeight > heightInfo.baseHeight }}"
      class="collapse {{show ? 'collapse-fold' : ''}}"
      bindtap="toggle" >
      {{show ? '收起' : '展开'}}
    </view>
    <!-- 用于获取一行高度dom -->
    <view class="get-height" >
      获取一行高度的盒子
    </view>
</view>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

js

// components/interceptText/interceptText.js.js
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    text: {
      type: String,
      value: ''
    },
    fontSize: {
      type: String,
      value: '28rpx'//  单位rpx
    }
  },

  /**
   * 组件的初始数据
   */
  data: {
    heightInfo: {
      baseHeight: 0,
      realHeight: 0
    },
    show: true,
    // 需要动态设置的外层盒子高度
    outerHeight: 0,
    paddingRight: 0
  },
  lifetimes: {
    async attached() {
      this.calculateHeight()
    },
  },
  /**
   * 组件的方法列表
   */
  methods: {
  /**
   * 动态获取展开文字宽度
   * 确保展开、收起文字能显示
   * **/ 
  async getCollapseWidth() {
    let res = await this.getHeight('.collapse')
    if(!res) return
    this.setData({
      paddingRight: `${res.width}` || 30
    })
  },  
  /**
   * 计算高度差,判断是否有省略号
   * **/ 
  async calculateHeight() {
    return Promise.all([this.getHeight('.get-height'),this.getHeight('.inner')]).then((res) => {
      let [baseRes,realRes] = res
      let baseHeight = parseInt(baseRes.height || 0)
      let realHeight = parseInt( realRes.height || 0)

      if(!baseHeight || !realHeight) {
        this.setData({
          outerHeight: 'auto',
        })
        return
      }
      this.setData({
        heightInfo: {
          baseHeight,
          realHeight
        },
        outerHeight: baseHeight,
        show: !(realHeight > baseHeight)
      })
      // 计算展开、收起
      wx.nextTick(() => {
        this.getCollapseWidth()
      })
    })
  },
  /**
   * 获取dom信息
   * **/ 
  getHeight(selector) {
    return new Promise((resolve,reject) => {
      const query = wx.createSelectorQuery().in(this)
      query.select(selector).boundingClientRect(function(res){
        resolve(res) 
      }).exec()
    })
  },
  /**
   * 展开状态切换
   * **/ 
  toggle() {
    this.setData({ 
      show: !this.data.show,
      outerHeight: this.data.show ? this.data.heightInfo.baseHeight : this.data.heightInfo.realHeight
    })
  },
  }
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100

css

.intercept{
  position: relative;
}
.outer{
  overflow: hidden;
}
.get-height{
  position: absolute;
  z-index: -9999;
  top: -100%;
  left: -100%;
  height: auto;
}
.ellipsis{
  display: -webkit-box;
  text-overflow: ellipsis;
  overflow: hidden;
  -webkit-line-clamp: 1;
  -webkit-box-orient: vertical;
}
.collapse{
  position: absolute;
  right: 0;
  bottom: 0;
  width: fit-content;
  color: #1989fa;
}
.collapse-fold{
  position: unset;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

5.0 总结

笔者认为,实现该功能的难点是如何判断当前行是否应该省略,这里采取一个高度差的办法,基本就没有兼容性问题,不过实际中发下,文字会有闪烁,这是因为高度都是动态计算导致的,展开、收起,可能改为插槽更合适点

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/77099
推荐阅读