Web版Excel制作过程分享
由于项⽬需要制作⼀个Web版本Excel⽤于表单、报表在线绘制,⽹上搜了⼀圈没有到合适的资源,根据搜到的⼀些零散信息决定⾃⼰动⼿做⼀个,本⽂分享这个制作过程,主要包含表格布局、表头固定、动态调整⾏⾼列宽、单元格选中、合并与拆分单元格等功能,供⼤家交流分享。废话少说先上个效果图如下:
⼀、技术选型
1. 本例基于Jquery库和Vue框架实现,其中Vue并不是必须,仅仅因为项⽬需要⽽已,读者只需稍作改造去掉对Vue 的依赖即可。
2. 出于对简单直观的追求,笔者选择基于table元素⽽不是基于div组合,
⼆、先⽤table做个Excel表格的样⼦
本来觉得很容易,⽤框架动态⽣成⼀个n⾏m列的table,并在第⼀⾏⾃动填充Z等作为列表头,在第⼀列⾃动填充等作为⾏表头,使⽤Vue框架v-for循环⽣成tr和td元素即可,不熟悉vue的同学可以简单了解⼀下vue中v-for 指令,当然也可以⽤原⽣js或jquery⽣成这个table的所有⾏列单元格,总体布局的思路如下:
1. 外层⽤⼀个div控制显⽰区域,让表格在这个区域内显⽰,超出该区域则滚动:overflow:scroll
2. 内层⽤table绘制表格,其中第⼀⾏和第⼀列单独绘制,填⼊表头字母和数字,每个单元格宽默认100px,tr⾏⾼默认28px
1<!DOCTYPE html>
2<html lang="zh" xmlns:v-bind="/1999/xhtml">
3<head>
4<meta charset="UTF-8">
5<title>Title</title>
6<script src="/jquery/2.1.1/jquery.min.js"></script>
7<script src="cdn.jsdelivr/npm/vue/dist/vue.js"></script>
8</head>
9<body>
10<div id="app">
11<div class="form-frame">
12<table class="form-table">
13<tr class="form-row">
14<th class="form-header" width="40px"></th>
15<th class="form-header" v-for="col in 26" width="100px">{{String.fromCharCode(col+64)}}</th>
16</tr>
17<tr class="form-row" v-for="row in 40">
18<td class="form-header" width="40px">{{row}}</td>
19<td class="form-cell" v-for="col in 26"></td>
20</tr>
21<tr></tr>
22</table>
23</div>html横向滚动条样式
24</div>
25<script>
26var vue = new Vue({
27 el:'#app'
28 });
29</script>
30<style>
31 .form-frame{
32 width: 700px;
33 height: 350px;
34 margin: 0 auto;
35 overflow:scroll;
36 border: 1px solid red;
37 }
38 .form-table{
39 border-spacing:0;
40 }
41 .form-header{
42 font-weight: normal;
43 text-align: center;
44 }
45 .form-row{
46 height: 28px;
47 }
48 th, td{
49 border-right: 1px solid;
50 border-bottom: 1px solid;
51 }
52 .form-cell{
53 width: 100px;
54 }
55</style>
56</body>
57</html>
View Code
结果如下图所⽰(红⾊是外层div的边框,为了调试⽅便),代码中我们给每个单元格设置了100px的宽度,⼀共⽣成了27列,按理说他应该把整个table撑开到⾄少2700px;然⽽如图所⽰整个table的宽度并没有被撑开,⽽是⾃适应了外层div的宽度。这就是我们今天要解决的第⼀个问题,table元素td标签宽度设置⽆效的问题。
三、解决table中td元素宽度设置⽆效的问题
⽹上有说给table添加table-layout: fixed样式,然⽽这种⽅法测试后并没效果;其实解决这个问题很简单,就是给table 直接指定⼀个明确的宽度,不妨我们先设个2700px看看效果
.form-table{
border-spacing:0;
width: 2700px;/*先指定⼀个明确的宽度*/
}
这时候我们发现整个table确实变宽了,div出现了横向滚动条(图下图所⽰),说明刚刚给table设置的2700px确实⽣效了;这也就是要求我们给table指定的宽度应该刚好是每⼀列的宽度之和,如果table宽度指定⼩了,那么他会从每⼀列中扣除多余的宽度,如果table宽度指定多了,他会给每⼀列加上相应的宽度,毕竟他要保证所有列不能超出table也不能填不满table。总之每个td的实际宽度会受到整个table的宽度影响,并不完全由td⾃⾝的width属性决定。
然⽽很多时候我们并不能预判我们到底有多少列,每⼀列到底有多宽,因此我们很难⼀开始就给table设定⼀个准确的宽度,解决这个问题的办法也很简单,就是额外添加⼀个不指定宽度的列,这个列我们称之为⾃适应列,有了这⼀列后,table就不需要指定⼀个准确的宽度,⽽是设置⼀个⽐预估宽度稍⼤⼀些的值,多出的这部分宽度都会由该列⾃适应,因此我们修改源码,添加⼀个⾃适应列:
<tr class="form-row">
<th class="form-header" width="40px"></th>
<th class="form-header" v-for="col in 26" width="100px">{{String.fromCharCode(col+64)}}</th>
<th></th><!--⾃适应列-->
</tr>
<tr class="form-row" v-for="row in 40">
<td class="form-header" width="40px">{{row}}</td>
<td class="form-cell" v-for="col in 26"></td>
<td></td><!--⾃适应列-->
</tr>
同时把table宽的设置为3000px:
.form-table{
border-spacing:0;
width: 3000px;/*设置⼀个稍⼤的宽度*/
}
效果如下图所⽰,最右侧这⼀列会⾃动适应多出的宽度,在不调整列宽的情况下这样就OK了。如果要调整列宽请看第五节内容。
关于table中td宽度的更多说明可以参考链接:wwwblogs/mqingqing123/p/6163140.html
四、解决table表头固定的问题
本例中table第⼀⾏和第⼀列都属于Excel表格的表头,需要固定不动。⽹上有解决⽅案就是使⽤两个table,⼀个做表头,⼀个做表⾝,这种⽅案只能解决列表头的问题,如果要同时解决固定⾏表头和列表头的问题,可能需要三个table,这样的⽅案会让页⾯布局变得⼗分复杂,难以维护,违背我们简单直观的初衷。
为了让代码尽量简洁⽽优雅,有没有基于当前这⼀个table的办法呢?当然有,⽹上已经有⼈介绍过了,那就是将表头采⽤relative布局,并通过滚轮事件实时更新表头位置:
1. 给第⼀⾏表头添加col-header类,给第⼀列表头添加row-header类,注意:左上⾓第⼀个单元格,既是⾏表头⼜是列表头
2. 给所有表头单元格设置样式position: relative,并加上底⾊(表头得看上去像表头的样⼦)
3. 监听外层div的滚动事件,实时更新列表头的top值为div的scrollTop值,实时更新⾏表头的left值为div的scrollLeft 值,这⼀步是关键,主要是保持表头的位置,让表头单元格不随着滚动条的滚动⽽移动。
html代码:
<tr class="form-row">
<th class="form-header col-header row-header" width="40px"></th>
<th class="form-header col-header" v-for="col in 26" width="100px">{{String.fromCharCode(col+64)}}</th>
<th class="form-header col-header"></th>
</tr>
<tr class="form-row" v-for="row in 40">
<td class="form-header row-header" width="40px">{{row}}</td>
<td class="form-cell" v-for="col in 26"></td>
<td></td>
</tr>
css代码:
.form-header{
font-weight: normal;
text-align: center;
position: relative;/*设置相对定位*/
background-color: #f7f7f7;/*表头背景⾊*/
}
js代码:
$(".form-frame").scroll(function () {
$(".col-header").css('top',$(".form-frame").scrollTop()); //实时更新第⼀⾏表头的位置,让他不随滚动条滚动⽽移动
$(".row-header").css('left',$(".form-frame").scrollLeft()); //实时更新第⼀列表头的位置,让他不随滚动条滚动⽽移动
})
效果如下图所⽰,可以实现内容滚动,⽽横竖表头都不动。
然⽽如图所⽰还有⼀点问题,就是左上⾓压盖的问题,这个问题也很简单,我们只需要把第⼀⾏第⼀列的单元的z-index值设置为1即可,让它始终在其他单元格上⾯就不会被覆盖了。
这种⽅案在chrome上表现⼗分完美,但是在ie会出现表头闪烁的问题,估计与ie触发滚动事件的频率或机制有关,如果对浏览器没有要求,那么⼗分推荐这种⽅式,如果⽆法容忍ie上的表头闪烁问题,那就只能另想办法了。
五、table动态调整列宽和⾏⾼
所谓动态调整列宽和⾏⾼,就是通过⿏标拖动表头单元格之间的分割线来实现⾏⾼和列宽的调整,可以参考这⼀⽚⽂章:blog.csdn/zanychou/article/details/46988529,基本思路如下:
1. 监听表头单元格的mousedown、mousemove和mouseup事件,
2. 通过⿏标坐标位置来判断是否处于可拖动区域,可以定义表头单元格分割线及其左右(上下)两边5px范围内为可拖动区域,如下图所⽰,
3. mousedown记录要调整的td及其原始宽度和坐标,mousemove实时计算新的宽度,mouseup结束拖动,
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论