Open Deol opened 7 years ago
后台系统中经常存在通过上传 Excel 导入数据的功能需求。
但运营方在使用该功能时经常会遇到这些问题:
换思路,若直接通过 Ctrl + C 和 Ctrl + V 复制粘贴 Excel 中的数据到页面中,上述问题似乎都能解决。
Ctrl + C
Ctrl + V
试试实际效果: 戳我
具体项目代码: 戳我
总共有 6 个剪贴板事件:
要访问剪贴板中的数据,可以使用 clipboardData 对象。
基本上在非 IE 类浏览器中,为了防止对剪贴板的未授权访问,只有在处理剪贴板事件期间 clipboardData 对象才能被访问。因此为了确保跨浏览器兼容性,建议在发生剪贴板事件期间使用该对象。
该对象有三个方法:getData()、setData() 和 clearData()。其中,getData() 用于从剪贴板中取得数据,它接受一个参数,一般为 text/plain,即要取得的数据的格式。
text/plain
富文本编辑很多时候可以由 div 模拟 textarea 文本框实现,只使用需要 contenteditable 属性。但此时若文本中包含样式,HTML 及样式信息也会被贴入。此时想要往在表格单项中粘贴纯文字,就需要做过滤。
从 W3C 规范草案 可知,contenteditable 分为以下几类:
那么,直接利用 contenteditable="plaintext-only" 就能解决问题。
contenteditable="plaintext-only"
/** * 获取剪贴板中的表格数据,并将其处理成可用的数据 * @param {Object} e */ getClipboardData(e = {}) { let clipboard = e.event.clipboardData; let data = clipboard.getData('text/plain').trim(); if(isSimpleString(data)) { return { type: 'string', data }; } return { type: 'table', data: data.split((/\r\n?/g)).map((row = {}) => { return row.split('\t').map(item => item.trim()); }).filter((item = {}) => { return item.some(subItem => !!subItem); }) }; }
执行粘贴操作
实现原理
实际上,除非当前粘贴数据为纯文本且粘贴位置为表格项中,此时直接利用 contenteditable="plaintext-only" 实现粘贴操作。
其它所有情况,都利用 e.preventDefault() 阻止默认事件,统一通过更新数据进而更新视图,利用数据驱动方式实现粘贴操作。
e.preventDefault()
/** * 粘贴操作,对用户进行粘贴的数据进行处理 * @param {Object} e */ paste(e) { let data = this.data; let { clipboard, table } = this.$refs; let excelInfo = this.getClipboardData(e); // 往表格中粘贴纯字符串时不做不做处理直接贴入,样式由单项的 contenteditable="plaintext-only" 去除 if(excelInfo.type === 'string') { // 在输入框中粘贴字符串时直接阻止 if([e.target, e.target.parentNode].indexOf(clipboard) > -1) { e && e.preventDefault(); window.alert('只能粘贴 Excel 表格数据哦~'); } return; } e && e.preventDefault(); // 未设置过数据时直接贴入表格 if(!ut.existTable(clipboard, table)) { this.updateClipboard(excelInfo.data); return; } // ...存在数据时的拼接覆盖处理逻辑 }
而在数据发生变更后,直接利用 {#include template} 方式使模板重新渲染。
{#include template}
/** * 更新操作区域的表格数据 * @param {Array} list * @param {Boolean} concat * @param {Number} reload */ updateClipboard(list = [], concat = false, reload = Math.random()) { let { clipboard, table } = this.$refs; // 拼接时,之前数据可能经过用户编辑,与当前 Model 不一致 let prevList = ut.getTableData(clipboard, table); Object.assign(this.data, { list: concat ? prevList.concat(list) : list, content: `${boardTpl}<input type="hidden" data-reload=${reload} />` }); this.$update(); }
在完成 Excel 数据的复制粘贴以及处理后,下一步可以将该表格与系统表格,进行表头项关联操作。
而若是贴入数据仅有一项或有对应规则,我们甚至可以执行自动绑定,简化操作流程。
利用 div 的 contenteditable="true" 可以实现 textarea 模拟功能,但是在 div placeholder 属性是不生效的。
contenteditable="true"
此时可以这么处理:
<!-- HTML --> <div data-placeholder="在这里粘贴从Excel表中复制的数据,注意确保粘贴表头哦~"></div> <!-- CSS --> <style> div:empty:before { content: attr(data-placeholder); } </style>
你好,这个能复制到datatables插件的表格里面吗?
title: 实现 Excel 纯前端复制粘贴 date: 2017-10-27
背景
后台系统中经常存在通过上传 Excel 导入数据的功能需求。
但运营方在使用该功能时经常会遇到这些问题:
换思路,若直接通过
Ctrl + C
和Ctrl + V
复制粘贴 Excel 中的数据到页面中,上述问题似乎都能解决。试试实际效果: 戳我
具体项目代码: 戳我
准备工作
总共有 6 个剪贴板事件:
要访问剪贴板中的数据,可以使用 clipboardData 对象。
基本上在非 IE 类浏览器中,为了防止对剪贴板的未授权访问,只有在处理剪贴板事件期间 clipboardData 对象才能被访问。因此为了确保跨浏览器兼容性,建议在发生剪贴板事件期间使用该对象。
该对象有三个方法:getData()、setData() 和 clearData()。其中,getData() 用于从剪贴板中取得数据,它接受一个参数,一般为
text/plain
,即要取得的数据的格式。富文本编辑很多时候可以由 div 模拟 textarea 文本框实现,只使用需要 contenteditable 属性。但此时若文本中包含样式,HTML 及样式信息也会被贴入。此时想要往在表格单项中粘贴纯文字,就需要做过滤。
从 W3C 规范草案 可知,contenteditable 分为以下几类:
那么,直接利用
contenteditable="plaintext-only"
就能解决问题。核心实现
执行粘贴操作
实现原理
实际上,除非当前粘贴数据为纯文本且粘贴位置为表格项中,此时直接利用
contenteditable="plaintext-only"
实现粘贴操作。其它所有情况,都利用
e.preventDefault()
阻止默认事件,统一通过更新数据进而更新视图,利用数据驱动方式实现粘贴操作。而在数据发生变更后,直接利用
{#include template}
方式使模板重新渲染。后续处理
在完成 Excel 数据的复制粘贴以及处理后,下一步可以将该表格与系统表格,进行表头项关联操作。
而若是贴入数据仅有一项或有对应规则,我们甚至可以执行自动绑定,简化操作流程。
其他总结
利用 div 的
contenteditable="true"
可以实现 textarea 模拟功能,但是在 div placeholder 属性是不生效的。此时可以这么处理: