ToB企服应用市场:ToB评测及商务社交产业平台
标题:
不是吧,刚毕业几个月的前端,就写这么复杂的表格??
[打印本页]
作者:
前进之路
时间:
前天 19:28
标题:
不是吧,刚毕业几个月的前端,就写这么复杂的表格??
前言
近来负责了项目的一个大迭代,但是有一个非常复杂的表格,怎么个复杂法呢。正常来说,我们前端的一个表格大多是使用ui框架中的现成表格组件,顶多就在表格内里内嵌一些输入框,选择框,改改内嵌样式什么的!但是这个表格,就真的很牛逼,给各人分享一下(如下),趁便记录一下。然后本人很菜,是个刚毕业的前端彩笔,看个乐子就行。
乍一看是不是也挺简朴,就这?反正对我来说,是开辟的想死了,我写这个表格使用三个饿了么的表格组件。是的,三个表格组件实现成同一个表格,常常写表格的大佬们应该一看就知道痛点在哪里了。
技能难点
表格的协同滚动
左右两个表格是要能够左右滚动
表格悬浮展示操作栏
屏幕中间有个信息栏穿越整个表格的
改变el-table的内置样式
为什么我要使用三个表格
如下图,左中右分别都是一个表格组件,为什么要这个写,细心的盆友可以看到1和3的表格是可以
左右滚动
的,从
盒模型
的角度来看,就不可能写在同一个元素中了,而且以我现在的工作经验来看,滚动好像只能使用原生的,顶多改变一下样式。至于2的话,应该是可以不用这个表格组件也能写的,但是我为了方便就如许写了,使用组件的话很多样式就可以cv了。
表格的协同滚动
前面说过,这个表格是由三个表格组件实现的,以是这个三个表格之间的协同滚动就非常的紧张了,
好比我在1表格上下滚动,2和3表格也要对应的举行滚动
,同理在2大概3表格中上下滚动,对应的其他两个表格也应该举行滚动。 另有就是
1表格和3表格是有一个镜像左右滚动
的。
如许听起来好像非常easy是吧,就是
给每个表格都监听滚动事故,滚动的时候去改变其余的两个表格滚动条
。对整体思路就是如许,但是我写着写着就
死循环
了哈哈哈哈哈。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
padding: 0;
margin: 0;
}
.box {
width: 800px;
height: 450px;
/* background-color: red; */
margin: 0 auto;
margin-top: 200px;
display: flex;
}
.common {
width: 300px;
height: 450px;
background-color: blue;
overflow: auto;
}
.middle {
width: 200px;
background-color: aqua;
overflow: auto;
}
.content {
height: 1000px;
}
</style>
</head>
<body>
<div class="box">
<div class="common" id="left">
<div class="content" style="width: 500px;"></div>
</div>
<div class="middle" id="middle">
<div class="content"></div>
</div>
<div class="common" id="right">
<div class="content" style="width: 500px;"></div>
</div>
</div>
<script>
const leftO = document.querySelector("#left")
const middleO = document.querySelector("#middle")
const rightO = document.querySelector("#right")
leftO.addEventListener("scroll", (e) => {
console.log("左表格")
const top = e.target.scrollTop
const left = e.target.scrollLeft
middleO.scrollTop = e.target.scrollTop
rightO.scrollTop = e.target.scrollTop
rightO.scrollLeft = left
},true)
middleO.addEventListener("scroll", (e) => {
console.log("中表格")
const top = e.target.scrollTop
leftO.scrollTop = e.target.scrollTop
rightO.scrollTop = e.target.scrollTop
},true)
rightO.addEventListener("scroll", (e) => {
console.log("右表格")
const left = e.target.scrollLeft
const top = e.target.scrollTop
leftO.scrollTop = e.target.scrollTop
middleO.scrollTop = e.target.scrollTop
leftO.scrollLeft = left
},true)
</script>
</body>
</html>
复制代码
这是一个小demo,各人可以复制一下去本地跑一下,可以发现
不管是上下滚动,照旧左右滚动,都是触发同一个滚动事故
去设置scrollTop大概scrollLeft也会触发滚动事故函数
也就是说,这三个表格,
任意一个表格滚动其实都是触发了三个表格的滚动事故
,固然这里是没有死循环的,由于我另有一个需求是在上下滚动的时候同时去改变左右滚动地方,以是就会导致
他调用她,她反过来又调用他
,以是就死循环了,背面是通过雷同
防抖
的写法去解决的(如下vue3的写法),为什么说他是雷同呢,由于它是三个事故函数去共用同一个防抖开关,以是他最后照旧会多执行一次,有爱好的大佬可以去试试。用这种写法也可以
减少函数执行次数
,也是一种
性能优化
哈哈哈哈。
// updateMassge和setLeftFn是两个方法就不具体写了
// 防抖开关
const flag = ref(null)
// 左表格滚动事件
const scrollLeftFn = e => {
const scrollLeft = e.target.scrollLeft
const scrollTop = e.target.scrollTop
clearTimeout(flag.value)
flag.value = setTimeout(() => {
console.log("左表格执行")
// updateMassge这个方法是去更新信息栏的一个方法,后面会有提到
updateMassge(scrollTop)
middleTable.value.setScrollTop(scrollTop)
rightTable.value.setScrollTop(scrollTop)
// 设置左右滚动
setLeftFn(scrollLeft)
})
}
// 右表格滚动事件
const scrollRightFn = e => {
const scrollLeft = e.target.scrollLeft
const scrollTop = e.target.scrollTop
clearTimeout(flag.value)
flag.value = setTimeout(() => {
console.log("右表格执行")
// updateMassge这个方法是去更新信息栏的一个方法,后面会有提到
updateMassge(scrollTop)
middleTable.value.setScrollTop(scrollTop)
leftTable.value.setScrollTop(scrollTop)
// 设置左右滚动
setLeftFn(scrollLeft)
})
}
// 中间表格滚动事件
const scrollMiddleFn = e => {
const scrollTop = e.target.scrollTop
clearTimeout(flag.value)
flag.value = setTimeout(() => {
console.log("中间表格执行")
// updateMassge这个方法是去更新信息栏的一个方法,后面会有提到
updateMassge(scrollTop)
})
}
复制代码
信息栏该怎么实现呢
我以为这应该是这个表格最抓马的地方了,为什么呢,这个表格整体由三个表格组件
横向排列
形成的,以是想要横穿这三个表格放一个div,只能让它
脱离文档流
,去父相子绝的定位它。更恶心的地方是这个信息栏的位置是
必要根据表格的数据去确定位置
,如下图,信息栏中的数字是143.59,那它的位置就应该是在143和144之间。大佬们可以思索一下要怎么实现呢?
我说说我是怎么做的。起首,前面说过只能通过
绝对定位
去脱离文档流,将它放到它应该放到的地方去。应该说是
覆盖
,对!在这个信息栏的下面其实是有一行假数据的。以是最紧张是去
正确的找到它的位置
(top)然后在表格滚动的时候
动态
的去更新它的位置也就是前面说的
updateMassge
方法,以及
如何控制它正确的显示和隐蔽
(display)由于在它滚动到顶部大概底部的时候应该把它隐蔽掉。
探求top
如何探求top呢,起首就是维护好一个下标变量,有点像之前写过的一个算法题,
一个有次序的数组,去找到他的插入位置,让这个数组依然有序
,我一开始使用的findIndex写的,然后项目提测 后在一些特定的数据会有bug哈哈哈,由于在findIndex没找到的时候返回值是-1,就会有一些问题。其实就是一个
二分法
就能解决!
function findInsertPosition(nums, target) {
let left = 0;
let right = nums.length - 1;
while (left <= right) {
let mid = Math.floor(left + (right - left) / 2);
if (nums[mid] === target) {
return mid;
} else if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return left;
}
复制代码
拿到这个下标索引之后,就是一些把他的计算公式写出来,我当时搁那拿本子画了很久哈哈哈,要找到表格滚动高度scrollTop和top的一个关系。
如图,可以得出
index * 行高 + 表头高 = scrollTop + top
以是
top = (index * 行高 + 表头高) - scrollTop
然后就是在
滚动的事故函数中去动态的更新top
以及去
探求出现信息栏和隐蔽信息栏的临界点
。
这个临界点也很好找,当
top小于0大概大于表格高度
的时候就隐蔽,其他时候就显示
表格悬浮展示操作栏
在前面的动态图中,可以看到这个表格,每
悬浮一列最左边大概最右边都会出现一个操作栏
,这个一开始不知道从何动手,由于我看element-ui中并没有提供能实现的这种效果的属性大概方法。不过照旧给我想出来办法来了,不得不说我照旧有点实力的哈哈哈哈哈。
其实实现起来也非常简朴,就是通过css的hover选择器去实现的,各人看一下伪代码应该就能明确是怎么实现的。
dom结构
<el-table ref="leftTable" :data="KZData">
// 操作列
<el-table-column label="" fixed="left" width="100px" align="center">
<template #default="scope">
<div class="operation-show red">
<div class="function-box">
<img src="图标地址"/>
<span>买</span>
<span>卖</span>
</div>
</div>
</template>
</el-table-column>
// 其他列
<el-table-column v-for="(item, index) in Column">
{{ scope.row[item.prop] }}
</el-table-column>
</el-table>
复制代码
样式
// 悬浮操作栏
.operation-show {
display: none;
}
.el-table__body tr:hover > td .operation-show {
display: block;
}
复制代码
是吧,是不是非常简朴,在最左边去
固定一个列去存放这些操作图标
,然后就是
css选择器
的使用,悬浮列的时候用选择器去选择到对应的div去改变他的display属性。
如何去改变饿了么组件的内部样式
这些ui组件都是自带样式的,而我们要根据ui设计图去开辟,以是学会去改变ui组件的内部样式是非常紧张的,而一般我们都是通过
样式穿透
去改变的
举个例子,当我们要改变el-table的样式时,起首必要将这个ui组件用盒子去包裹一层,并给定一个类名,用这个类名举行样式穿透。
<div class="left-table">
<el-table>
</el-table>
</div>
复制代码
然后就是使用::v-deep去选定内置组件的类名大概标签名,然后在内里编写你想要的样式,至于内置组件的相关信息就必要使用F12
检查
去查看了。
.left-table {
::v-deep(.el-table-fixed-column--left) {
border-right: 1px solid red;
}
::v-deep(.el-table-fixed-column--right) {
border-right: 1px solid red;
}
::v-deep(.cell) {
padding: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
::v-deep(.el-table thead th) {
font-weight: 400;
}
}
复制代码
原文链接:https://juejin.cn/post/7428980575821234230
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/)
Powered by Discuz! X3.4