电商网站的后台总少不了各种繁杂数据的录入,旁边的运营妹子录完第138条商品的时候,终于忍不住转身吼到:为什么后台的录入表不能像Excel那样多行粘贴!!!于是,就有了这片文章~
实现的就是这样的一个效果,从Excel或Number复制好多行数据后,直接在table起始单元格按下C+V,表格数据立马就齐刷刷站好位了!强迫症表示看着好爽感!
原理:绑定表格的粘贴事件,取消默认事件,解析粘贴板中的数据为以行和单元格分开的数组,然后按照表格格式输出到input的value中。
开发过程中遇到的问题总结起来主要有三个:
1.对粘贴板中表格数据的拆分需要兼容不同软件的复制格式。IOSNumbers,WindowsExcel和IOSExcel之间都有细微的差别。
表格软件在复制数据时,通过制表符
\t
来分隔行内不同单元格数据,通过换行符\n
或回车符\r
来分隔不同行的数据。我们在测试中通过console.log打印数据,这些转义符会自动转换成空格或换行,为使这些转义符通过字符的形式直接输出,我们需要对数据进行简单的转码,将\t
替换成\\\\t
,以此类推。
测试代码如下:
var clipboardData = window.clipboardData || e.originalEvent.clipboardData,
data = clipboardData.getData('Text'); // 获取到粘贴板数据,兼容IE || chrome
console.log(data.replace(/\n/g, '\\n').replace(/\t/g, '\\t').replace(/\r/g, '\\r'));
不同表格软件复制格式测试结果:
结果分析: 行内的不同单元格分隔都使用’\t’,而换行分隔有使用’\n”\r’两种情况。而且在windows系统的excel,末行的最后还会加上一个换行符。
兼容这三个软件的最终解析粘贴板数据代码如下:
//获取粘贴板数据
var clipboardData = window.clipboardData || e.originalEvent.clipboardData, // IE || chrome
data = clipboardData.getData('Text'),
//判断表格数据是使用\n还是\r分行,解析成行数组
rowArr = (data.indexOf(String.fromCharCode(10)) > -1) ?
data.split(String.fromCharCode(10)) :
data.split(String.fromCharCode(13)),
//根据\t解析单元格
cellArr = rowArr.filter(function(item) {
return (item !== "") //兼容windowsExcel行末\n,防止粘贴出多余空行
}).map(function(item) {
return item. split(String.fromCharCode(9));
});
2.将数组中的数据插入web table 时,防止粘贴数据超出表格边界
用户在复制的时候,很可能复制的行数或列数超出web table的总行总列数,因此我们在进行行或列的循环‘粘贴’时,除了判断循环数i/j小于复制数据的行/列数外,还要判断当前所在行/列是否小于表格的总行/列数;
最终代码如下:
//输出至网页表格
var tab = $(e.target).parents('table')[0], //表格
td = $(e.target).parents('td'), //当前单元格
startRow = td.parents('tr')[0].rowIndex, //当前单元格行数
startCell = td[0].cellIndex, //当前单元格列数
rows = tab.rows.length; //总行数
for (var i = 0; i < cellArr.length && startRow + i < rows; i++) {
var cells = tab.rows[startRow + i].cells.length; //该行总列数
for(var j = 0; j < cellArr[i].length && startCell + j < cells; j++) {
var cell = tab.rows[startRow + i].cells[startCell + j];
$(cell).find(':text').val(cellArr[i][j]);
}
}
3.粘贴后很可能需要进行表单验证或其他操作,可以以回调函数的形式实现。
最终代码:
$.fn.pasteFromTable = function(cb) { //make it a jquery function
$(this).bind('paste', function(e) {
e.preventDefault(); //消除默认粘贴
//获取粘贴板数据
var clipboardData = window.clipboardData || e.originalEvent.clipboardData, // IE || chrome
data = clipboardData.getData('Text'),
//判断表格数据是使用\n还是\r分行,解析成行数组
rowArr = (data.indexOf(String.fromCharCode(10)) > -1) ?
data.split(String.fromCharCode(10)) :
data.split(String.fromCharCode(13)),
//根据\t解析单元格
cellArr = rowArr.filter(function(item) { //兼容Excel行末\n,防止粘贴出多余空行
return (item !== "")
}).map(function(item) {
return item. split(String.fromCharCode(9));
});
//输出至网页表格
var tab = $(e.target).parents('table')[0], //表格
td = $(e.target).parents('td'), //当前单元格
startRow = td.parents('tr')[0].rowIndex, //当前单元格行数
startCell = td[0].cellIndex, //当前单元格列数
rows = tab.rows.length; //总行数
for (var i = 0; i < cellArr.length && startRow + i < rows; i++) {
var cells = tab.rows[startRow + i].cells.length; //该行总列数
for(var j = 0; j < cellArr[i].length && startCell + j < cells; j++) {
var cell = tab.rows[startRow + i].cells[startCell + j];
$(cell).find(':text').val(cellArr[i][j]);
if (cb) {cb(cell)};
}
}
})
}
上面代码为了方便引用,将方法绑在了jQuery.function中了。只要调用表格jquery对象的pasteFromTable方法, 就可以华丽丽的实现多单元格复制了。
$('table').pasteFromTable(function(cell){
//cell 为当前单元格dom
});
测试用例和完整代码可移步github