小程序自制自带滑动条的表格组件

  • 在编写过程中遇到的难点
    • 1. 表格的编写
    • 2. 表格内容宽度固定 长度自适应
    • 3. 滚动条逻辑及代码编写
    • 4. 滚动条的卡段优化
    • 5. 小程序组件的编写及应用
  • 尾声

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

在编写过程中遇到的难点

  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.heightvar _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();},

尾声

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

小程序自制自带滑动条的表格组件相关推荐

  1. 小程序 onReachBottom 事件快速滑动时不触发的bug

    一般在列表页面 会先加载一定数量的数据 触发上拉加载这个动作的时候再陆续加载数据 假如上拉一次加载10条数据 在小程序中 你快速滑动页面触发加载这个事件的话 你会发现小程序卡着不动了 刚开始以为数据加 ...

  2. 微信小程序实现点击导航条切换页面

    本文实例为大家分享了微信小程序实现点击导航条切换页面的具体代码,供大家参考,具体内容如下 我录制了个gif如下,黄色部分是不可以滑动的,蓝色部分可以滑动. 代码解说: 首先我在js自定义了navSta ...

  3. 小程序禁用ios 左右滑动_如何在使用应用程序时禁用iOS控制中心

    小程序禁用ios 左右滑动 The Control Center has proven to be a thoughtful and welcome addition to iOS, but it c ...

  4. 微信小程序禁止页面上下滑动;uni-app微信小程序禁止页面上下滑动;uni-app小程序上下滑动;

    阻止小程序某个页面上下滑动,最简单有效方法:直接对小程序当前页的最外层标签盒子,设置固定定位即可! 设置固定定位后,页面的最大盒子宽度可能不是自动撑满的,那就自己在calc计算下宽度即可 .box { ...

  5. 外卖菜谱小程序源码-带流量主功能-外卖领劵个人也可过审

    简介: 站长点评:这套小程序优点就带很多菜谱,各种你爱吃菜的做法与各类食材介绍营养搭配,相信很多小姐姐会感兴趣. 宝妈宝爸这个小程序肯定能留的住这个群体的人脉流量,这是小程序最大的亮点:其它功能也没有 ...

  6. 最新酒桌小游戏喝酒小程序源码/带流量主

    2022最新酒桌小游戏喝酒小程序源码,带流量主:喝酒神器3.6,我修改增加了广告位,根据文档直接替换即可,原版本没有广告位 直接上传源码到开发者端即可,通过后改广告代码,然后关闭广告展示提交,通过后打 ...

  7. 字体设计符号组合多功能微信小程序源码 带流量主

    这是一款主打字体设计,符号组合等多模板功能的一款微信小程序源码 内含多种功能,比如: 花式字体设计 表情字体组合设计 翅膀字体组合 火星文一键生成 符号库 空白名称 彩色网名等等 还有很多,所以就不一 ...

  8. 校园跑腿微信小程序跑腿同学带直播新版源码

    校园跑腿微信小程序跑腿同学带直播新版源码 适用类型 微信小程序 测试环境:系统环境:CentOS Linux 7.6.1810 (Core).运行环境:宝塔 Linux v7.0.3(专业版).网站环 ...

  9. 九宫格心形拼图小程序源码/带流量主微信小程序源码

    九宫格心形拼图小程序源码/带流量主微信小程序源码 ☑️ 编号:ym476 ☑️ 品牌:无 ☑️ 语言:微信小程序 ☑️ 大小:500KB ☑️ 类型:九宫格心形拼图 ☑️ 支持:微信小程序

最新文章

  1. GitHub 轻松提速教程
  2. MyBatis小问题(1)-Mapper中错误No constructor found...
  3. iOS键盘弹出通知后加入动画
  4. java定义list_我的Java Web之路59 - Java中的泛型
  5. python barrier_Python线程障碍对象Barrier原理详解
  6. Python basestring函数- Python零基础入门教程
  7. 矩阵的四个基本子空间
  8. VUE-用到的样式左右(transform,translate,padding)
  9. jfinal分页时使用like
  10. 什么是次梯度(次导数)
  11. 保存/读取图片到数据库
  12. 计算机中反三角函数怎么算,计算器怎么算反三角函数?
  13. c4d安装oc后打开计算机丢失,c4d+oc的安装及使用的全过程
  14. 计算机无法投影,电脑无法识别投影仪-电脑为什么检测不到投影仪,应该怎么安装...
  15. Just Do It!
  16. ubuntu将主文件夹的文件夹中文名称改为英文
  17. 单核CPU如何执行多线程
  18. Android-小游戏
  19. 萌新的C语言指针小结(1)
  20. 圣诞节快要来了,可我就是_我的圣诞节愿望清单

热门文章

  1. Oracle数据库:自然连接natural join,using语句,注意避免写交叉连接
  2. 字符和文档识别的四十年研究
  3. mysql where 加引号和不加引号
  4. Linux 磁盘管理 : mount 命令详解
  5. Java 判断平衡二叉树
  6. css overflow属性及使用方法(场景)
  7. journald.conf 中文手册
  8. Hadoop认识初体验
  9. KNIME的学习使用心得
  10. 使用vue2实现打印在线word文件,文件流形式打印在线word,预览打印