客服工单系统里有一张设备登记表,其中一列要填产品型号。型号库里有几百个条目,名称长得还像:PRO-2000、PRO-2000S、PRO2-K。从几百项的下拉里翻找和凭记忆手打,体验都糟糕。用户想要的是第三种交互------打两个字母,候选浮出来,点一下填好。这就是常见的自动完成(autocomplete):SpreadJS 单元格默认没有这个能力,但留了把它接进去的口子。
思路:把现成的编辑器挂进单元格
SpreadJS 提供了基类 GC.Spread.Sheets.CellTypes.Base,自定义单元格类型继承它之后可以接管单元格的整个编辑生命周期:createEditorElement 创建编辑器 DOM、activateEditor 激活时绑定行为、deactivateEditor 退出时清理、getEditorValue 在提交前决定什么值允许写入。
做法很直接:让 createEditorElement 返回一个 input 元素,在 activateEditor 里对它初始化 jQuery UI 的 autocomplete 组件,把候选词数组交给 source。再补一个细节------获得焦点时就调一次 search,不输字符也能看到候选。退出编辑时调用 autocomplete('destroy') 清理实例,避免事件残留。
javascript
AutocompleteCellType.prototype = new GC.Spread.Sheets.CellTypes.Base();
AutocompleteCellType.prototype.createEditorElement = function () {
return document.createElement("input");
};
AutocompleteCellType.prototype.activateEditor =
function (editorContext, cellStyle, cellRect, context) {
$(editorContext).autocomplete({
minLength: 0,
source: this.availableTags
}).focus(function () {
$(this).autocomplete('search', $(this).val());
});
// 标记为 SpreadJS 编辑器元素,点击候选项时不丢失焦点
$(editorContext).autocomplete("widget")
.attr("gcUIElement", "gcEditingInput");
return $(editorContext);
};
gcUIElement 值得单独说一句:它是 SpreadJS 识别自己 UI 元素的标记,把下拉候选面板也标上它,鼠标点到候选上时表格才不会误判为"点了外面"而结束编辑。
只靠提示还不够,要把口子也收住
自动完成只是引导,挡不住越界输入。粘贴进来一个不在候选里的值怎么办?这份实现给了三道补充闸门。
第一道在提交时:重写 getEditorValue,检查输入是否在 source 里,不在且配置为不可自定义(示例中的 isEditable 开关)就返回 null,这次编辑等于没发生。第二道在粘贴后:监听 Events.ClipboardPasted 事件,遍历粘贴区域,凡是自动完成列的单元格,值不在候选集里就清空。第三道在键盘上:重写 isReservedKey,编辑状态下把上下方向键声明为单元格类型自己处理,上下键用来在候选列表里移动,不会被表格抢去切换选中单元格。
另外,整列应用用的是 sheet.getRange(-1, 1, -1, 1).cellType(...);再配一个 cellButtons 下拉按钮,回调里用 startEdit(false) / endEdit(true) 切换编辑状态,点一下就能展开全部候选。
可以扩展到哪些场景
凡是"选项多到下拉翻不动、但取值范围有限"的字段都适用:物料编码、客户名称、会计科目。配合 minLength 还能做检索优化------字典量大时设为 2 或 3,敲够几个字符才发起匹配,避免一次渲染上千个候选。数据源换成接口返回的异步数组,就是一张联网联想录入表。
给开发者的关键词
GC.Spread.Sheets.CellTypes.Base、createEditorElement、activateEditor、deactivateEditor、getEditorValue、isReservedKey、cellButtons、startEdit、endEdit、Events.ClipboardPasted、autocomplete、minLength。
小结
这个方案的本质,是把 Web 世界成熟的输入组件嫁接进电子表格的编辑体系:Base 类管生命周期,autocomplete 管联想,三个小钩子守住数据边界。代码量不大,却同时照顾到录入效率和数据质量两端。