网页版仿Excel效果组件--handsontable拓展运用
引言(祝看官们新年万事大吉)
前段时间项目需要实现网页版的excel表格功能,瞬间就想到了handsontable,为什么呢?理由如下:该UI组件功能齐全多样,展示效果也更贴近bootstrap风格,兼容所有现代浏览器和IE9+,然后开源,api相当给力。
唯一美中不足的是没有中文版的api,也有些分享中文api的文章,也不完整(有就不错了,不满意自己去看官网api啊,啦啦啦~),闲言少叙,进入正文:
功能需求
我们先看一下功能操作栏(红框部分为部分我们需要实现的功能):
上图中的 input 会同步响应我们所选单元格的数据,其他的方法如图所示。
首先我们既然是表格,那么我们的操作对象基本都是单元格,但同时我们肯定也希望能够满足范围性操作,比如说批量修改样式。当然我们不仅需要考虑到展示效果,还需要考虑到储存和数据渲染,
我们需要的做到以下几点:所选范围、所选范围里的单元格、如何储存数据、如何通过loadData一次性加载数据(包括样式及自定义属性),带着这些问题我们去看api,我们需要找到我们需要方法以及了解如何使用它们。
这里附上官方api链接:https://docs.handsontable.com/pro/1.16.0/tutorial-introduction.html
阅读过程小生这里就不做赘述了(唔...一把辛酸泪),首先我们需要清楚的是,我们需要获取到被选择的单元格对象,而要获取单元格对象我们要知道所选范围(单个单元格也是一个范围,这里不需要另作判断),而要知道所选范围我们要用到 getSelected() 方法,而此方法应该在我们选择范围后触发,所以我们需要用到钩子函数:afterOnCellMouseDown,具体用法可以到api里自行查阅
根据我们的需求,结合api得到如下图:
万事俱备,接下来该做什么呢?当然是做我们最爱做的事:撸代码!~
实现功能
我们这里用本地数据做展示:
var data = [
[, , , , , , , , , , , , , , , , , , , , ],
["2001", 10, 11, 12, 13,14,15,16,17,18,19,20,21,22,22,3,3,55,66,5,8,6,3,9,6,3,5,6,3,5,3,87,6,8,5,6,6,35,6,3,6,3,8,38,3],
["2002", 10, 11, 12, 13,14,15,16,17,18,19,20,21,22,22,3,3,55,66,5,8,6,3,9,6,3,5,6,3,5,3,87,6,8,5,6,6,35,6,3,6,3,8,38,3],
["2003", 10, 11, 12, 13,14,15,16,17,18,19,20,21,22,22,3,3,55,66,5,8,6,3,9,6,3,5,6,3,5,3,87,6,8,5,6,6,35,6,3,6,3,8,38,3],
["2004", 10, 11, 12, 13,14,15,16,17,18,19,20,21,22,22,3,3,55,66,5,8,6,3,9,6,3,5,6,3,5,3,87,6,8,5,6,6,35,6,3,6,3,8,38,3],
["2005", 10, 11, 12, 13,14,15,16,17,18,19,20,21,22,22,3,3,55,66,5,8,6,3,9,6,3,5,6,3,5,3,87,6,8,5,6,6,35,6,3,6,3,8,38,3],
["2006", 10, 11, 12, 13,14,15,16,17,18,19,20,21,22,22,3,3,55,66,5,8,6,3,9,6,3,5,6,3,5,3,87,6,8,5,6,6,35,6,3,6,3,8,38,3],
["2007", 10, 11, 12, 13,14,15,16,17,18,19,20,21,22,22,3,3,55,66,5,8,6,3,9,6,3,5,6,3,5,3,87,6,8,5,6,6,35,6,3,6,3,8,38,3],
["2008", 10, 11, 12, 13,14,15,16,17,18,19,20,21,22,22,3,3,55,66,5,8,6,3,9,6,3,5,6,3,5,3,87,6,8,5,6,6,35,6,3,6,3,8,38,3],
["2009", 20, 11, 14, 13,14,15,16,17,18,19,20,21,22,22,3,3,55,66,5,8,6,3,9,6,3,5,6,3,5,3,8,6,78,5,6,6,35,6,3,6,3,8,38,3],
["2010", 30, 15, 12, 13,14,15,16,17,18,19,20,21,22,22,3,3,55,66,5,8,6,3,9,6,3,52,6,3,5,3,8,6,8,5,6,56,355,6,3,66,23,8,38,3],
["2011", 20, 11, 14, 13,14,15,16,17,18,19,20,21,22,22,3,3,55,66,5,8,6,3,9,26,3,5,26,3,5,3,8,6,8,5,56,6,35,6,3,6,23,8,38,3],
["2012", 20, 11, 14, 13,14,15,16,17,18,19,20,21,22,22,3,3,55,666,5,8,6,3,9,6,3,5,56,3,5,3,78,6,58,55,6,6,35,6,23,6,3,8,38,3],
["2013", 20, 11, 14, 13,14,15,16,17,18,19,20,21,22,22,3,3,55,66,5,68,6,3,9,6,3,5,26,3,5,3,8,6,8,5,6,6,35,6,3,6,3,8,38,3],
["2014", 20, 11, 14, 13,14,15,16,17,18,19,20,21,22,22,3,3,55,66,5,8,6,3,9,6,3,5,26,3,5,3,8,6,58,5,6,6,35,6,3,6,3,8,38,3],
["2015", 20, 11, 14, 13,14,15,16,17,18,19,20,21,22,22,3,3,55,66,5,8,6,3,29,26,3,5,6,3,5,3,78,76,8,5,6,6,35,6,3,6,3,8,38,3],
["2016", 20, 11, 14, 13,14,15,16,17,18,19,20,21,22,22,3,3,55,66,5,8,6,3,9,6,3,55,6,3,5,3,8,6,28,5,6,6,35,6,3,6,3,8,38,3],
["2017", 20, 11, 14, 13,14,15,16,17,18,19,20,21,22,22,3,3,55,66,5,8,6,43,9,6,3,5,6,3,5,3,8,6,8,5,6,6,35,6,3,6,3,8,38,3],
["2018", 20, 11, 14, 13,14,15,16,17,18,19,20,21,22,22,3,3,55,66,5,8,62,3,29,6,3,5,6,3,5,3,8,6,8,5,6,6,35,6,3,6,3,8,38,3],
["2019", 20, 11, 14, 13,14,15,16,17,18,19,20,21,22,22,3,3,55,66,5,48,6,3,9,6,3,5,6,3,5,3,8,6,8,5,6,6,35,6,3,6,3,8,38,3],
["2020", 20, 11, 14, 13,14,15,16,17,18,19,20,21,22,22,3,3,55,66,5,68,6,3,9,6,3,5,6,3,5,3,8,6,8,5,6,6,345,6,3,64,3,8,38,3],
["2021", 20, 11, 14, 13,14,15,16,17,18,19,20,21,22,22,3,3,55,66,5,8,6,3,9,6,3,5,6,3,5,3,8,6,8,5,6,6,35,6,3,6,3,8,38,3],
["2022", 20, 11, 14, 13,14,15,16,17,18,19,20,21,22,22,3,3,55,66,5,8,6,3,9,66,3,5,6,3,5,3,8,6,8,5,6,6,35,6,3,6,3,48,38,23]
];
前端界面如图:
汉化右键菜单:如果不需要右键菜单可以设置为false,contextMenu : false
contextMenu: {
items: {
'mergeCells':{ name: '合并单元格' , },
'row_above': { name: '上方添加一行', },
'row_below': { name: '下方添加一行', },
'col_left': { name: '左侧添加一列', },
'col_right': { name: '右侧添加一列', },
'remove_row': { name: '移除此行', },
'remove_col': { name: '移除此列', },
'copy': { name: '复制', },
'cut': { name: '剪切', },
'make_read_only': { name: '禁止编辑选中项', },
'alignment': { },
'undo': { name: '还原上次操作', },
'redo': { name: '重复上次动作', },
'setAlias':{
name:'设置别名',
callback:function(){
if( $(Ccell) != undefined ){
addAliasDialog();
}else{
alert("请先选择单元格...");
}
}
}
}
}
看效果图:
自定义菜单及回调函数:自定义菜单也是在 contextMenu里面,格式如下(如上图中的 setAlias 设置别名,设置属性方法我们在后面再说明):
contextMenu: {
items: {
'参数名':{
name:'菜单名',
callback:function(){
// doSomething
}
}
}
}
列出全局变量:
// 列出全局变量
var Crow,Ccol,Ccell,valT,selectRange,selectRangeArr = [];
Crow:所选单元格的行,Ccol:所选单元格的列,valT:所选单元格的值,selectRange:所选范围,selectRangeArr:所选单元格数组
获取所选区域单元格数组,当前单元格高亮:这里需要补充的一点是,handsontable本身在表格失去焦点时会移除所有当前高亮类,而我们在点击按钮修改样式时又需要所选高亮来满足我们的“心中有数”,所以这里我们需要自定义一个高亮的类,看代码:
// 获取所选区域单元格数组 当前高亮
hot.addHook('afterOnCellMouseDown', function (event, cellCoords) {
Crow = cellCoords.row,
Ccol = cellCoords.col;
selectRangeArr = []; // 所选区域所有单元格数组
Ccell = hot.getCell(Crow, Ccol)
selectRange = hot.getSelected(); // 获取所选区域范围
console.log(selectRange);
var txt = hot.getDataAtCell(selectRange[0],selectRange[1]); // 获取所选区域第一个单元格值
// 单击任意单元格取消编辑状态
$(".handsontableInputHolder").css({
"display":"none"
});
$("#templateCellInput").val(txt);
var rangeRowArr = []; // 所选区域行数组
var rangeColArr = []; // 所选区域列数组
for( var i=selectRange[0];i<selectRange[2]+1;i++ ){
rangeRowArr.push(i);
}
for( var i=selectRange[1];i<selectRange[3]+1;i++ ){
rangeColArr.push(i);
}
for( var i=0;i<rangeRowArr.length;i++ ){
for( var n=0;n<rangeColArr.length;n++ ){
var selectRangeCell = { row:rangeRowArr[i],col:rangeColArr[n] };
selectRangeArr.push(selectRangeCell);
}
}
// 添加表格失去焦点时的当前单元格类
$("td").removeClass("currentTd");
for( var i=0;i<selectRangeArr.length;i++ ){
var rangeCell = hot.getCell(selectRangeArr[i].row, selectRangeArr[i].col);
$(rangeCell).addClass("currentTd");
}
});
我们可以在控制台查看一下令我们心动的 selectRange 和 selectRangeArr :
所选单元格的值和input同步:templateCellInput 为 input的id
$("#templateCellInput").keyup(function(){
var val = $(this).val();
if(selectRangeArr.length>0){
for( var i=0;i<selectRangeArr.length;i++ ){
hot.setDataAtCell(selectRangeArr[i].row, selectRangeArr[i].col,val)
}
}
});
修改单元格样式(字体样式和对齐方式):switch条件语句在这种事件触发对象判断中用起来是相当地令人愉快..
// 修改单元格样式
$(".btn-group label.btn").click(function(e){
console.log(e.target);
var _index = $(this).index();
var styleType = $(this).parent();
var StyleClassName = '';
// 修改单元格文本样式
var toggleSwitch = true;
if( styleType.hasClass("fontStyle") ){
var fontClass = "";
switch(_index){
case 0 : fontClass = "htBold"; // 加粗
break;
case 1 : fontClass = "htItalic"; // 斜体
break;
case 2 : fontClass = "htUnderline"; // 下划线
break;
}
StyleClassName = fontClass;
}
// 修改单元格对齐方式
if( styleType.hasClass("alignStyle") ){
var alignClass = "";
switch(_index){
case 0 : alignClass = "htLeft"; // 左对齐
break;
case 1 : alignClass = "htCenter"; // 居中对齐
break;
case 2 : alignClass = "htRight"; // 右对齐
break;
case 3 : alignClass = "htJustify"; // 两端对齐
break;
}
StyleClassName = alignClass;
}
// 修改所选区域所有单元格样式并赋予属性
for( var i=0;i<selectRangeArr.length;i++ ){
var rangeCell = hot.getCell(selectRangeArr[i].row, selectRangeArr[i].col);
var checkMergeCell = $(rangeCell).attr("rowspan");
$(rangeCell).removeClass("htLeft htCenter htRight htJustify");
// 定义修改类名 创建对应属性方法
var setRangeCellClass = function(){
$(rangeCell).toggleClass(StyleClassName);
var cellClass = $(rangeCell)[0].className;
hot.setCellMeta(selectRangeArr[i].row, selectRangeArr[i].col,"cellClass",cellClass);
}
if( checkMergeCell != undefined ){
if( toggleSwitch ){
setRangeCellClass();
toggleSwitch = false;
}else{
continue;
}
}else{
setRangeCellClass();
}
}
});
这里需要注意的两点是:
1、如果对象是合并单元格,那么在赋值和修改样式上需要区别对待,看代码(具体区别请调试代码自己体会o(∩_∩)o );
2、在方法里我们可以看到运用了 setCellMeta() 方法,单纯的前端效果我们不需要用到此方法,这里是为了便于储存和渲染数据,如此在初始化表格渲染数据的时候我们能将每一个单元格所对应的样式类名也添加进去,简而言之:每一次初始化表格我们只需要渲染一次,开心~
自定义背景色、字体颜色、边框色:这里我们用到了插件 bootstrap-colorpicker.js :
$(".ColorStyle input").each(function(){
$(this).colorpicker();
})
$(".ColorStyle input").blur(function(){
var val = $(this).val();
var _index = $(this).parent().index();
$(this).css("cssText","background:"+val+"!important;color:"+val+"!important;");
// 定义改变样式方法
var changeCellStyle = function(){
if( _index == 0 ){
$(rangeCell).css({"background":val});
hot.setCellMeta(selectRangeArr[i].row, selectRangeArr[i].col,"bkColor",val);
}
if( _index == 1 ){
$(rangeCell).css({"color":val});
hot.setCellMeta(selectRangeArr[i].row, selectRangeArr[i].col,"ftColor",val);
}
if( _index == 2 ){
$(rangeCell).css({"border":"solid 1px "+val});
hot.setCellMeta(selectRangeArr[i].row, selectRangeArr[i].col,"bdColor",val);
}
};
for( var i=0;i<selectRangeArr.length;i++ ){
var rangeCell = hot.getCell(selectRangeArr[i].row, selectRangeArr[i].col);
var checkMergeCell = $(rangeCell).attr("rowspan");
if( checkMergeCell != undefined ){
if( toggleSwitch ){
changeCellStyle();
toggleSwitch = false;
}else{
continue;
}
}else{
changeCellStyle();
}
}
});
看效果图:
自定义属性:假设我们现在需要给某些单元格添加任意属性,这里我们以设置别名为例,并且希望能在右键菜单中可以直接操作:
'setAlias':{
name:'设置别名',
callback:function(){
if( $(Ccell) != undefined ){
addAliasDialog();
}else{
alert("请先选择单元格...");
}
}
}
对的,此处应该有弹窗,这里小生强烈推荐用 layer.js,快准狠还高大上...这里附上 layer.js的官网地址,具体用法有空亲们可以自行琢磨:http://www.layui.com/doc/modules/layer.html,下面看设置别名回调函数:
function addAliasDialog(){
var html = '<div class="alias" style="text-align:center;margin-top:20px;"><label>请输入别名:<input type="text" id="aliasVal" /></label></div>';
layer.open({
type: 1,
btn: ['确认', '取消'],
shadeClose:true,
title:"设置别名",
area: ['420px', '240px'], //宽高
content: html,
yes:function(index,layero){
var val = $("#aliasVal").val();
var cellMeta = hot.getCellMeta(Crow, Ccol);
if( val != "" ){
hot.setCellMeta(Crow, Ccol, "alias", val);
layer.msg('设置成功', {
icon: 1,
time: 1000 //1秒关闭(如果不配置,默认是3秒)
}, function(){
console.log(cellMeta);
layer.close(index);
});
}else{
alert("别名不能为空!");
}
},
cancel:function(index,layero){
layer.close(index);
},btn2: function(index, layero){
layer.confirm('确认取消设置别名吗?', {icon: 3, title:'提示'}, function(index){
layer.close(index);
},function(index){
addAliasDialog();
});
}
});
}
这里需要注意的一点是,setCellMeta添加的属性是单元格的属性,而不是单元格的DOM属性,所以我们用attr或者prop方法是获取不到的(小生不可能告诉亲们当初经历了什么~),我们可以在设置完成以后将所选单元格的属性打印出来:
看打印结果
:
结语
这次分享到这里就结束了,希望对大家有所帮助,有疑问或者建议都可以留言交流,新年快乐,摸摸踹~
网页版仿Excel效果组件--handsontable拓展运用的更多相关文章
- Qt高仿Excel表格组件-支持冻结列、冻结行、内容自适应和合并单元格
目录 一.概述 二.效果展示 三.实现思路 1.冻结行.冻结列 2.行高自适应 3.蚂蚁线 四.测试代码 1.添加表格数据 2.设置冻结行.列 3.行高.列宽 4.单元格背景色 5.单元格文字 6.其 ...
- 自已开发完美的触摸屏网页版仿app弹窗型滚动列表选择器/日期选择器
手机端网页版app在使用下拉列表时,传统的下拉列表使用起来体验非常不好,一般做的稍好一点的交互功能界面都不会直接使用下拉列表,所以app的原生下拉列表都是弹窗列表选择,网页型app从使用体验上来当然也 ...
- Handsontable-一款仿 Excel效果的表格插件使用总结 96
最近在做一个关于报表管理的项目,发现了一款很好用的jQuery插件-Handsontable.它真的特别给力,在 Excel 中可进行的操作,你几乎都可以在网页中做到,如拖动复制.Ctrl+C .Ct ...
- Android用RecyclerView实现的二维Excel效果组件
excelPanel 二维RecyclerView.不仅可以加载历史数据,而且可以加载未来的数据. 包括在您的项目中 excelPanel 二维RecyclerView.不仅可以加载历史数据,而且 ...
- 前端练手小项目——网页版qq音乐仿写
qq音乐网页版仿写 一些步骤与注意事项 一开始肯定就是html+css布局和页面了,这段特别耗时间,耐心写完就好了 首先要说一下大致流程: 一定要先布局html!,所以一定要先分析页面布局情况,用不同 ...
- html5 contenteditable 实现table可编辑(网页版EXCEL)
一直想找一个免费的网页版的EXCEL插件,以便于多人共同在线编辑,始终没发现合适的. 其实自己实现类似功能也不难.参考:https://blog.csdn.net/chadcao/article/de ...
- Vue3.0网页版聊天|Vue3.x+ElementPlus仿微信/QQ界面|vue3聊天实例
一.项目简介 基于vue3.x+vuex+vue-router+element-plus+v3layer+v3scroll等技术构建的仿微信web桌面端聊天实战项目Vue3-Webchat.基本上实现 ...
- 基于React.js网页版弹窗|react pc端自定义对话框组件RLayer
基于React.js实现PC桌面端自定义弹窗组件RLayer. 前几天有分享一个Vue网页版弹框组件,今天分享一个最新开发的React PC桌面端自定义对话框组件. RLayer 一款基于react. ...
- Android -- 真正的 高仿微信 打开网页的进度条效果
(本博客为原创,http://www.cnblogs.com/linguanh/) 目录: 一,为什么说是真正的高仿? 二,为什么要搞缓慢效果? 三,我的实现思路 四,代码,内含注释 五,使用方法与截 ...
随机推荐
- 【开发技术】Eclipse插件Call Hierarchy简介及设置
Call Hierarchy 主要功能是 显示一个方法的调用层次(被哪些方法调,调了哪些方法) 在MyEclipse里Help - Software updates - Find and instal ...
- 单词拼写检查之cutoff距离
前言 cutoff是一个比较冷门的概念,相比于DP经典算法的编辑距离,cutoff距离只局限于自然语言处理领域.提出cutoff距离的起因很简单,因为经典的编辑距离无法很好地衡量在字符串搜索过程中的编 ...
- SQLServer分页查询模板
SELECT TOP 10 * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY id) AS RowNumber,* FROM ERPTelFile ) A WHE ...
- 利用mk-table-checksum监测Mysql主从数据一致性操作记录
前面已经提到了mysql主从环境下数据一致性检查:mysql主从同步(3)-percona-toolkit工具(数据一致性监测.延迟监控)使用梳理今天这里再介绍另一种Mysql数据一致性自动检测工具: ...
- set&enum小结(database)
今天发现mysql中有set这种数据类型,工作的业务中也使用到了.网上查阅资料后,小结一下 先总结一下两者的分别 set和enum类似表单中的多选和单选,set和enum在数据库内部是用整数表示的,显 ...
- 苹果系统css样式变化
原因:苹果自带样式覆盖了 参考文章比较详细,就不自己写了,copy了一份~~~ @参考文章 只要在样式里面加一句去掉css去掉iPhone.iPad的默认按钮样式就可以了!~ input[type=& ...
- MyEclipse中设置注释模板的方法
1.选择菜单Window→Preferences. 2.选择Java→Code style→Code Templates→Commets.选中具体的分类如Methods,点击右侧的Edit可以设置对应 ...
- Win2003 设置远程连接限制数
在开发过程中,很多同事需要连接到一台Win2003服务器,但是连接人数超过了10个,就连接不上了.想设置一下连接限制数,可以如下操作: 1:在运行里面输入gpedit.msc后,弹出"本地计 ...
- nginx配置中root与alias的区别
nginx指定文件路径有两种方式root和alias,这两者的用法区别,使用方法总结了下,方便大家在应用过程中,快速响应.root与alias主要区别在于nginx如何解释location后面的uri ...
- JQuery Ajax 设置请求头信息application/json
今天有个api后台接application/json格式的 在Jquery里$.ajax默认是contentType: application/x-www-form-urlencoded; chars ...