找回密码
 立即注册

QQ登录

只需一步,快速开始

Derrick.Jiao 讲师达人认证 悬赏达人认证 SpreadJS 开发认证
论坛元老   /  发表于:2022-2-22 15:21  /   查看:2649  /  回复:0
本帖最后由 Derrick.Jiao 于 2022-2-22 15:32 编辑

背景:在一些实际的使用场景中,有的朋友有这样一个需求,根据用户输入的字符,去后台ajax查询,动态加载数据到下拉列表中。我们知道,想要实现下拉列表,可以用,list实现,这是学习指南的链接,但是原生的list不支持搜索以及模糊匹配。https://demo.grapecity.com.cn/sp ... p-downs/list/purejs

于是我们可以通过自定义单元格来实现,就像下面这个demo。但是,下面这个demo,又可能不太满足需求,demo的数据是hardcode的,并且不能像list那样,去存储类似的键值对。
https://demo.grapecity.com.cn/Sp ... /demos/autoComplete

那么这篇帖子就是教大家如何实现一个满足搜索,并且能够从后台查询的这样一个自定义单元格。那这个自定义单元格需要与第三方的插件配合,能够让我们事半功倍,这样我们就只要专注于自定义单元格的逻辑即可。整体逻辑就是,查询到响应的lastname,那么就会返回这个那么与id,查询不到,那么也能正常填写,id为-1。
value.gif593401488.png


另外,这个插件叫Select2,是一款基于JQuery的下拉列表插件,主要用来优化select,支持单选和多选,同时也支持分组显示、列表检索、远程获取数据等众多好用的功能。这是项目地址:https://select2.org/ ,感兴趣的朋友可以去了解一下。没时间也不用担心,我在demo中做了“保姆级”的注释,包教包会,不会再来~

在开始前,我已经默认你是会自定义单元格了,如果还不太会,可以看下我们学习指南的教程
https://demo.grapecity.com.cn/sp ... types/custom/purejs

那我们就开始吧。我们先指定一个typeName,并且挂在window上, 这样spread可以通过typeName进行查找。主要用在序列化与反序列化以及自定义单元格的复制粘贴
  1. function AutoCompleteCellType() {
  2.             this.typeName = "MyAutoComplete";
  3.         }

  4.         window["MyAutoComplete"] = AutoCompleteCellType;
复制代码

下一步就是继承base这个cellType,这里就不赘述了。再往下我们就是要进行方法的重写,第一个就是重写createEditorElement。该方法的意思是创建编辑元素,因为在每次进入编辑状态是都会创建编辑框,这个时候就会触发createEditorElement来创建编辑框相关元素。在该方法中我们一般将编辑框的基本dom元素建立起来,并作为上下文return出去。
  1. AutoCompleteCellType.prototype.createEditorElement = function (context) {
  2.             var editor;
  3.             editor = document.createElement("div");

  4.             //声明了这个属性之后,该dom会被SpreadJS认为是SpreadJS本身的一部分,这样在SpreadJS本身的生命周期做处理的时候也会包含该dom
  5.             editor.setAttribute("gcUIElement", "gcEditingInput");
  6.             editor.appendChild(document.createElement("select"));
  7.             editor.children[0].style.width = "100%";
  8.             editor.children[0].style.height = "100%";

  9.             //获取单元格的矩阵区域宽高,并给到select2作为其宽高
  10.             var cellRect = context.sheet.getCellRect(context.row, context.col);
  11.             editor.style.width = cellRect.width + "px";
  12.             editor.style.height = cellRect.height + "px";

  13.             //监听选中,选择完成后结束编辑
  14.             $(editor).find("select").on("select2:select", function (e) {
  15.                 context.sheet.endEdit();
  16.             });

  17.             //监听open,对于自定义的元素,需要添加gcUIElement属性,
  18.             //如果元素或者其父元素没有该属性,点击创建的组件便会直接退出编辑状态无法编辑
  19.             $(editor).find("select").on("select2:open", function (e) {
  20.                 $(".select2-dropdown").attr("gcUIElement", "gcEditingInput");
  21.             });

  22.             return editor;
  23.         };
复制代码

接着就是绘制在单元格上进行绘制的paint方法。这里面我们实际不需要在上面做其他设置所以直接调用apply,执行在canvas上绘制[id:value]的形式。
  1. AutoCompleteCellType.prototype.paint = function (ctx,value,x,y,w,h,style,options) {
  2.             if (value) {
  3.                 GC.Spread.Sheets.CellTypes.Base.prototype.paint.apply(this, [ctx,value.id + ": " + value.value,x,y,w,h,style,options,]);
  4.             }
  5.         };
复制代码

再下来就是触发编辑器的方法activateEditor。该方法在每次激活编辑状态时触发,触发的顺序是先触发createEditorElement之后再触发activateEditor,并且activateEditor中可以获取到eContext这个上下文,该上下文就是createEditorElement返回的结果。这里面,我们通过ajax去请求我们的数据源,拿到数据源后,我们可以通过select2的内置的方法进行搜索和匹配。
  1.     AutoCompleteCellType.prototype.activateEditor = function (eContext,cellStyles,cellRect) {
  2.                 $(eContext).find("select").select2({
  3.                     ajax: {
  4.                         url: "https://raw.githubusercontent.com/kshkrao3/JsonFileSample/master/select2resp.json",
  5.                         // url:"http://localhost/data.json",
  6.                         dataType: "json",
  7.                         delay: 250,
  8.                         data: function (params) {
  9.                             return {
  10.                                 q: params.term, // search term
  11.                                     
  12.                             };
  13.                         },
  14.                         processResults: function (data, params) {
  15.                         // parse the results into the format expected by Select2
  16.                             var resData = [];
  17.                             console.log(data)
  18.                             data.forEach(function (value) {
  19.                                 if (value.LastName.indexOf(params.term) != -1) resData.push(value);
  20.                             });
  21.                             resData = $.map(resData, function (item) {
  22.                                 return {
  23.                                     text: item.LastName,
  24.                                     id: item.Id,
  25.                                 };
  26.                             });
  27.                             if (resData.length === 0) {
  28.                                 resData.push({
  29.                                     text: params.term,
  30.                                     id: -1,
  31.                                 });
  32.                             }
  33.                             return {
  34.                                 results: resData,
  35.                             };
  36.                         },
  37.                         cache: true,
  38.                     },
  39.                     minimumInputLength: 1,
  40.                 });

  41.                 setTimeout(() => {
  42.                     $(eContext).find("select").select2("open");
  43.                 });
  44.             };
复制代码
当我们查询完成后,需要将下拉框销毁,用的也是select2的方法
  1. AutoCompleteCellType.prototype.deactivateEditor = function (eContext, context) {
  2.             $(eContext).find("select").select2("destroy");
  3.         };
复制代码

再接着就是关于编辑器与单元格之间值的设置与获取,我们可以重写下面两个方法,将单元格的值以遮掩给一个id+value的对象返回。
  1.   AutoCompleteCellType.prototype.getEditorValue = function (eContext) {
  2.                 var data = $(eContext).find("select").select2("data");
  3.                 if (!data || !data.length) {
  4.                     return null;
  5.                 }
  6.                 return Object.assign(
  7.                     {},
  8.                     {
  9.                         id: data[0].id,
  10.                         value: data[0].text,
  11.                     }
  12.                 );
  13.             };
  14.             AutoCompleteCellType.prototype.setEditorValue = function (eContext, val) {
  15.                 if (!val) {
  16.                     return;
  17.                 }

  18.                 var op = new Option(val.value, val.id, true, true);
  19.                 $(eContext).find("select").append(op).trigger("change");
  20.             };
复制代码

最后就是处理保留键。例如当按键为以下按键时,按下箭头下键return true也就是不会进入下一个单元格,而是在自定义的列表中向下选择。其他也是同理。
  1.    AutoCompleteCellType.prototype.isReservedKey = function (e, context) {
  2.                 if (
  3.                     context.isEditing &&
  4.                     (e.keyCode == 40 || e.keyCode == 38 || e.keyCode == 13 || e.keyCode == 27)
  5.                 ) {
  6.                     return true;
  7.                 }
  8.                 return GC.Spread.Sheets.CellTypes.Text.prototype.isReservedKey.apply(
  9.                     this,
  10.                     arguments
  11.                 );
  12.             };
复制代码

以上就是关于这个自定义单元格的讲解,最重要还是拿到代码亲自试一试。以防请求的数据丢失,这边也单独把这个json上传,后续也可以部署在本地进行访问测试~


data.json

1.83 KB, 下载次数: 145

autoComplete_update.html

8.84 KB, 下载次数: 113

0 个回复

您需要登录后才可以回帖 登录 | 立即注册
返回顶部