IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 小程序自制自带滑动条的表格组件 -> 正文阅读

[移动开发]小程序自制自带滑动条的表格组件

先上最终效果图,表格可以上下、左右滑动,表格内容宽度固定,高度自适应内容大小,附上滑动条,滑动条长度宽度也是自适应表格的。
在这里插入图片描述

在编写过程中遇到的难点

  1. 表格的编写,小程序无table标签,需要自己用view+flex布局编写。
  2. 表格内容宽度固定,长度自适应。
  3. 滚动条逻辑及代码编写。
  4. 滚动条的卡段优化。
  5. 小程序组件的编写及应用。

1. 表格的编写

之前写过一篇简单利用view以及flex布局编写表格的文章。
链接: 小程序绘制表格table(表头固定,可上下左右滑动).

2. 表格内容宽度固定 长度自适应

当把表格填写进去后发现当内容宽度大于表格宽度时,居然不会换行,直接溢出。。
在这里插入图片描述
后来搜索了一下发现view是不会自动换行的,需要在.th .tr样式里加上这句:

/* view换行 */
white-space: pre-line;

/* 内容文字居中 */
display: flex;
justify-content: center;
align-items: center;
text-align: center;

加上后就变成了这样:
在这里插入图片描述

3. 滚动条逻辑及代码编写

为什么要自制滑动条呢,明明微信的scrollview有自带滑动条的功能:
在这里插入图片描述
自带的滑动条很好,也足够我们用了,但是!为什么ios的横向滑动条不显示啊????我搜索了一番发现我不是个例,于是我就开始自己编写滑动条,对了记得把小程序自带的滑动条屏蔽,因为安卓用户是显示的。用show-scrollbar="false"也是不生效的,需要在wxss中添加以下代码片段:

/* 隐藏原有的进度条 */
::-webkit-scrollbar {
  display: none;
  width: 0;
  height: 0;
  color: transparent;
}

滚动条的编写逻辑参考了这篇文章:https://www.cnblogs.com/jiechen/p/4712631.html
在这里插入图片描述
主要是抓准一个比例关系:滚动条总长度 :滚动条长度 = 层级2 :层级1
由于滚动条的总长度通常与层级1的高度一致,所以:滚动条的长度 = (层级1 * 层级1)/ 层级2

当表格滑动时,滑动条也要跟着滑动,因此我们需要计算出滑动条滑动的距离:
首先算出滑动比例 = 滑动条可滑动距离 / 表格可滑动距离;
即:滑动比例 =(滑动条总长度 - 滑动条长度)/(层级2 - 层级1)= (层级1 - 滑动条长度)/(层级2 - 层级1)
那么滑动条需要滑动的距离= 滑动比例 * 层级滑动的距离
层级滑动的距离小程序已经在scrollview组件中给了我们:
在这里插入图片描述
以上逻辑形成js代码片段如下:

data: {
    // x滑动条
    sliderWidth: '', //滑块宽度
    barWidth: '', //滑动条宽度
    totalWidth: '', //表格整体宽度
    slideRatioX: '', //比例
    slideLeft: '', //滑动距离
},
methods: {
  	getRatioX: function (e) {
      var query = wx.createSelectorQuery().in(this);
      var _totalWidth = 0;

      // 获取整体表格宽度
      query.select("#tableContent").boundingClientRect((res) => {
        _totalWidth = res.width;
      }).exec()

      // 计算比例
      query.select('#tableX').boundingClientRect((res) => {
        var _barWidth = res.width; //滑动条总宽度
        var _showWidth = (_barWidth * _barWidth) / _totalWidth; //计算滑块宽度
        var _ratio = (_barWidth - _showWidth) / (_totalWidth - _barWidth); //滚动列表长度与滑条长度比例
        this.setData({
          sliderWidth: _showWidth, //滑块宽度
          barWidth: _barWidth, //滑动条宽度
          totalWidth: _totalWidth, //表格整体宽度
          slideRatioX: _ratio, //比例
        })
      }).exec()
    },
}
  

滑动事件:

//在<scroll-view>标签里加上bindscroll="getleft"
<scroll-view scroll-x="true" bindscroll="getleft">
	//...
</scroll-view>

//滑动条的html
<view class="slidex">
	<view class='slidex-bar' id="barWidth" style="width: {{barWidth}}px;">
		<view class="slidex-show" id="sliderWidth" style="width: {{sliderWidth}}px;margin-left:{{slideLeft}}"></view>
	</view>
</view>

//js文件中
getleft: function (e) {
   this.setDate({
   		slideLeft: e.detail.scrollTop * this.data.slideRatioX
   });
}

4. 滚动条的卡段优化

原本滑动条的部分到这里就结束了,我在用调试测试的时候也好好的,直到我试了一下真机调试。。。
滑动条卡到我怀疑人生,明明表格已经滑到最后了,但是滑动条还要隔两三秒才滑动。。。

后面排查了一轮发现是小程序通信耗时的问题,官方文档中也给出了我们解决方案:
链接: WXS响应事件.
在这里插入图片描述
这就好办了,我们只需要把滑块移动的函数写成WXS函数就完事了!
更改代码如下:


// html 
<wxs module="wxs" src="./table.wxs"></wxs> //引入wxs文件
//增加bind:scroll="{{wxs.onScrollX}}" 并传入比例值data-slideratiox="{{slideRatioX}}"
<scroll-view class="tableX" scroll-x bind:scroll="{{wxs.onScrollX}}" data-slideratiox="{{slideRatioX}}">
	//...
</scroll-view>

// wxs
var onScrollX = function(e, ownerInstance) {
  var scrollBarBlockLeft = e.detail.scrollLeft * e.currentTarget.dataset.slideratiox;
  ownerInstance.selectComponent('#sliderWidth').setStyle({"margin-left": scrollBarBlockLeft + 'px'});
}
module.exports = {
  onScrollX: onScrollX
};

//滑动条html 可以删除margin-left:{{slideLeft}}部分
<view class="slidex">
	<view class='slidex-bar' id="barWidth" style="width: {{barWidth}}px;">
		<view class="slidex-show" id="sliderWidth" style="width: {{sliderWidth}}px;"></view>
	</view>
</view>

5. 小程序组件的编写及应用

由于表格在项目的多处地方用到,所以把它做成组件的形式比较方便复用。
小程序组件的学习参考了这篇文章:链接: 微信小程序 基础3【组件化开发、自定义组件、全栈开发、使用Express】.
在这里插入图片描述
直接上代码把~

html部分:

<!--components/table/table.wxml-->
<wxs module="wxs" src="./table.wxs"></wxs>
<view class="table">
    <view style="width: 99%;display: flex; justify-content: center;">
        <scroll-view class="tableX" id="tableX" scroll-x show-scrollbar="false" bind:scroll="{{ wxs.onScrollX }}"
            data-slideratiox="{{slideRatioX}}">
            <view id="tableHeader" style="display: inline-block;width: {{totalWidth}}px;">
                <!-- slot -->
                <slot name="tableheader"></slot>
                <!-- /slot -->
            </view>
            <scroll-view class="tableY" id="tableY" scroll-y show-scrollbar="false"
                style="height: {{tableHeight}};width: {{totalWidth}}px;" bind:scroll="{{ wxs.onScrollY }}"
                data-slideratioy="{{slideRatioY}}">
                <view id="tableContent" style="display: inline-block">
                    <!-- slot -->
                    <slot name="tablecontent"></slot>
                    <!-- /slot -->
                </view>
            </scroll-view>
        </scroll-view>
        <!--滚动条Y部分-->
        <view class="slide" wx:if="{{slideBarYshow}}" style="height: {{barHeight}}px;margin-top: {{tableTopHeight}}px;">
            <view class='slide-bar' id="barHeight" style="height: {{barHeight}}px;">
                <view class="slide-show" id="slideHeight" style="height:{{slideHeight}}px;"></view>
            </view>
        </view>
    </view>
    <!--滚动条X部分-->
    <view class="slidex">
        <view class='slidex-bar' id="barWidth" style="width: {{barWidth}}px;">
            <view class="slidex-show" id="sliderWidth" style="width: {{sliderWidth}}px;"></view>
        </view>
    </view>
</view>

wxss部分:

/* components/table/table.wxss */
.table {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
.tableX {
  border: 1px solid #dadada;
  white-space: nowrap;
  border-right: 0;
  border-bottom: 0;
  width: 93%;
}
 .tableY {
  display: flex;
  justify-content: flex-start;
  white-space: nowrap;
}
.tr{
  display: flex;
  justify-content: flex-start;
}
.th,.td {
  width: 300rpx;
  padding: 10px 0;
  border-bottom: 1px solid #dadada;
  border-right: 1px solid #dadada;
  text-align: center;
}
.th {
  font-weight: bold;
}

/* Y滑动条 */
.slide {
  width: 10rpx;
  margin-left: 20rpx;
  position: relative;
}

.slide .slide-bar {
  position: absolute;
  width: 5rpx;
  margin: 0 auto;
  background: #eee;
}

.slide .slide-bar .slide-show {
  height: 100%;
  background-color: #0b97f5;
}

/* X滑动条 */
.slidex {
  width: 99%;
  height: 10rpx;
  display: flex;
  justify-content: center;
  margin-top: 10rpx;
}
.slidex-bar {
  width: 700rpx;
  height: 5rpx;
  background-color: #eee;
}
.slidex-show {
  height: 100%;
  background-color: #0b97f5;
}

/* 隐藏原有的进度条 */
::-webkit-scrollbar {
  display: none;
  width: 0;
  height: 0;
  color: transparent;
}

js部分:

// components/table/table.js
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    tableHeight: { // 属性名
      type: String,
      value: '',
      observer: function (newVal, oldVal) {
        // 属性值变化时执行
        // console.log("new:" + newVal);
        if (newVal == '100%') {
          this.setData({
            slideBarYshow: false,
          })
        } else {
          this.setData({
            slideBarYshow: true,
          })
        }
      }
    },
  },
  //多处slot必须开启multipleSlots: true,
  options: {
    multipleSlots: true,
  },

  /**
   * 组件的初始数据
   */
  data: {
    // y滑动条
    slideBarYshow: true, //是否显示滑块
    slideHeight: '', //滑动块高度(与表格-表头 保持一致)
    barHeight: '', //滑动条高度(跟表格内容同高)
    totalHeight: '', //表格整体高度
    slideRatioY: '', //比例
    tableTopHeight: 0, //表头高度

    // x滑动条
    sliderWidth: '', //滑块宽度
    barWidth: '', //滑动条宽度
    totalWidth: '', //表格整体宽度
    slideRatioX: '', //比例
  },

  /**
   * 组件的方法列表
   */
  methods: {

    getRatioY: function (e) {
      var query = wx.createSelectorQuery().in(this);
      var _totalHeight = 0;

      // 获取表头高度
      query.select("#tableHeader").boundingClientRect((res) => {
        this.setData({
          tableTopHeight: res.height
        })
      }).exec()

      // 获取整体表格高度
      query.select("#tableContent").boundingClientRect((res) => {
        _totalHeight = res.height;
        // console.log("_totalHeight:" + _totalHeight)
      }).exec()
      // 计算比例
      query.select('#tableY').boundingClientRect((res) => {
        var _barHeight = res.height
        var _showHeight = (_barHeight * _barHeight) / _totalHeight; //当前显示滑条的长度
        var _ratio = (_barHeight - _showHeight) / (_totalHeight - _barHeight); //滚动列表长度与滑条长度比例
        this.setData({
          barHeight: _barHeight,
          slideHeight: _showHeight,
          totalHeight: _totalHeight,
          slideRatioY: _ratio
        })
      }).exec()

    },

    getRatioX: function (e) {
      var query = wx.createSelectorQuery().in(this);
      var _totalWidth = 0;

      // 获取整体表格宽度
      query.select("#tableContent").boundingClientRect((res) => {
        _totalWidth = res.width;
      }).exec()

      // 计算比例
      query.select('#tableX').boundingClientRect((res) => {
        var _barWidth = res.width;
        var _showWidth = (_barWidth * _barWidth) / _totalWidth;
        var _ratio = (_barWidth - _showWidth) / (_totalWidth - _barWidth); //滚动列表长度与滑条长度比例
        this.setData({
          sliderWidth: _showWidth, //滑块宽度
          barWidth: _barWidth, //滑动条宽度
          totalWidth: _totalWidth, //表格整体宽度
          slideRatioX: _ratio, //比例
        })
      }).exec()
    },
  }
})

json文件:

{
  "component": true,
  "usingComponents": {}
}

wxs文件:

var onScrollY = function(e, ownerInstance) {
  var scrollBarBlockLeft = e.detail.scrollTop * e.currentTarget.dataset.slideratioy;
  ownerInstance.selectComponent('#slideHeight').setStyle({"margin-top": scrollBarBlockLeft + 'px'});
}

var onScrollX = function(e, ownerInstance) {
  var scrollBarBlockLeft = e.detail.scrollLeft * e.currentTarget.dataset.slideratiox;
  ownerInstance.selectComponent('#sliderWidth').setStyle({"margin-left": scrollBarBlockLeft + 'px'});
}
module.exports = {
  onScrollY: onScrollY,
  onScrollX: onScrollX
};

在使用过程中还发现了两个细节问题:
1. 多处使用slot必须在js文件中添加:multipleSlots: true, 还要给slot添加name属性。

//多处slot必须开启
  options: {
    multipleSlots: true,
  },

2. 当使用组件并传入值,且值会动态变化时,此处属性值变化有延迟:

properties: {
    tableHeight: { // 属性名
      type: String,
      value: '',
      observer: function (newVal, oldVal) {
        // 属性值变化时执行
        // console.log("new:" + newVal);
        if (newVal == '100%') {
          this.setData({
            slideBarYshow: false,
          })
        } else {
          this.setData({
            slideBarYshow: true,
          })
        }
      }
    },
  },

所以你需要在调用修改后的值的方法那加上延迟函数:

// 获取修改后高度有延迟
setTimeout(() => {
	this.table.getRatioY();
}, 300);

3. 调用组件的顺序不能错:定义组件 > 获取数据 > 调用组件函数

onShow: function () {
	//定义组件
    this.table = this.selectComponent("#table");
    //获取数据
    this.changeList();
    this.changeMenu();
    //调用组件函数
    this.table.getRatioY();
    this.table.getRatioX();
  },

尾声

到这,基本上所有的问题都解决了~ 这次项目对于我一个新手来说确实很有挑战性,但也在其中学到了很多东西,希望能坚持记录自己成长路上遇到的问题!

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-10-24 15:02:38  更:2021-10-24 15:03:43 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:40:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码