本帖最后由 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。
另外,这个插件叫Select2,是一款基于JQuery的下拉列表插件,主要用来优化select,支持单选和多选,同时也支持分组显示、列表检索、远程获取数据等众多好用的功能。这是项目地址:https://select2.org/ ,感兴趣的朋友可以去了解一下。没时间也不用担心,我在demo中做了“保姆级”的注释,包教包会,不会再来~
在开始前,我已经默认你是会自定义单元格了,如果还不太会,可以看下我们学习指南的教程
https://demo.grapecity.com.cn/sp ... types/custom/purejs
那我们就开始吧。我们先指定一个typeName,并且挂在window上, 这样spread可以通过typeName进行查找。主要用在序列化与反序列化以及自定义单元格的复制粘贴
- function AutoCompleteCellType() {
- this.typeName = "MyAutoComplete";
- }
- window["MyAutoComplete"] = AutoCompleteCellType;
复制代码
下一步就是继承base这个cellType,这里就不赘述了。再往下我们就是要进行方法的重写,第一个就是重写createEditorElement。该方法的意思是创建编辑元素,因为在每次进入编辑状态是都会创建编辑框,这个时候就会触发createEditorElement来创建编辑框相关元素。在该方法中我们一般将编辑框的基本dom元素建立起来,并作为上下文return出去。
- AutoCompleteCellType.prototype.createEditorElement = function (context) {
- var editor;
- editor = document.createElement("div");
- //声明了这个属性之后,该dom会被SpreadJS认为是SpreadJS本身的一部分,这样在SpreadJS本身的生命周期做处理的时候也会包含该dom
- editor.setAttribute("gcUIElement", "gcEditingInput");
- editor.appendChild(document.createElement("select"));
- editor.children[0].style.width = "100%";
- editor.children[0].style.height = "100%";
- //获取单元格的矩阵区域宽高,并给到select2作为其宽高
- var cellRect = context.sheet.getCellRect(context.row, context.col);
- editor.style.width = cellRect.width + "px";
- editor.style.height = cellRect.height + "px";
- //监听选中,选择完成后结束编辑
- $(editor).find("select").on("select2:select", function (e) {
- context.sheet.endEdit();
- });
- //监听open,对于自定义的元素,需要添加gcUIElement属性,
- //如果元素或者其父元素没有该属性,点击创建的组件便会直接退出编辑状态无法编辑
- $(editor).find("select").on("select2:open", function (e) {
- $(".select2-dropdown").attr("gcUIElement", "gcEditingInput");
- });
- return editor;
- };
复制代码
接着就是绘制在单元格上进行绘制的paint方法。这里面我们实际不需要在上面做其他设置所以直接调用apply,执行在canvas上绘制[id:value]的形式。
- AutoCompleteCellType.prototype.paint = function (ctx,value,x,y,w,h,style,options) {
- if (value) {
- GC.Spread.Sheets.CellTypes.Base.prototype.paint.apply(this, [ctx,value.id + ": " + value.value,x,y,w,h,style,options,]);
- }
- };
复制代码
再下来就是触发编辑器的方法activateEditor。该方法在每次激活编辑状态时触发,触发的顺序是先触发createEditorElement之后再触发activateEditor,并且activateEditor中可以获取到eContext这个上下文,该上下文就是createEditorElement返回的结果。这里面,我们通过ajax去请求我们的数据源,拿到数据源后,我们可以通过select2的内置的方法进行搜索和匹配。
- AutoCompleteCellType.prototype.activateEditor = function (eContext,cellStyles,cellRect) {
- $(eContext).find("select").select2({
- ajax: {
- url: "https://raw.githubusercontent.com/kshkrao3/JsonFileSample/master/select2resp.json",
- // url:"http://localhost/data.json",
- dataType: "json",
- delay: 250,
- data: function (params) {
- return {
- q: params.term, // search term
-
- };
- },
- processResults: function (data, params) {
- // parse the results into the format expected by Select2
- var resData = [];
- console.log(data)
- data.forEach(function (value) {
- if (value.LastName.indexOf(params.term) != -1) resData.push(value);
- });
- resData = $.map(resData, function (item) {
- return {
- text: item.LastName,
- id: item.Id,
- };
- });
- if (resData.length === 0) {
- resData.push({
- text: params.term,
- id: -1,
- });
- }
- return {
- results: resData,
- };
- },
- cache: true,
- },
- minimumInputLength: 1,
- });
- setTimeout(() => {
- $(eContext).find("select").select2("open");
- });
- };
复制代码 当我们查询完成后,需要将下拉框销毁,用的也是select2的方法- AutoCompleteCellType.prototype.deactivateEditor = function (eContext, context) {
- $(eContext).find("select").select2("destroy");
- };
复制代码
再接着就是关于编辑器与单元格之间值的设置与获取,我们可以重写下面两个方法,将单元格的值以遮掩给一个id+value的对象返回。
- AutoCompleteCellType.prototype.getEditorValue = function (eContext) {
- var data = $(eContext).find("select").select2("data");
- if (!data || !data.length) {
- return null;
- }
- return Object.assign(
- {},
- {
- id: data[0].id,
- value: data[0].text,
- }
- );
- };
- AutoCompleteCellType.prototype.setEditorValue = function (eContext, val) {
- if (!val) {
- return;
- }
- var op = new Option(val.value, val.id, true, true);
- $(eContext).find("select").append(op).trigger("change");
- };
复制代码
最后就是处理保留键。例如当按键为以下按键时,按下箭头下键return true也就是不会进入下一个单元格,而是在自定义的列表中向下选择。其他也是同理。
- AutoCompleteCellType.prototype.isReservedKey = function (e, context) {
- if (
- context.isEditing &&
- (e.keyCode == 40 || e.keyCode == 38 || e.keyCode == 13 || e.keyCode == 27)
- ) {
- return true;
- }
- return GC.Spread.Sheets.CellTypes.Text.prototype.isReservedKey.apply(
- this,
- arguments
- );
- };
复制代码
以上就是关于这个自定义单元格的讲解,最重要还是拿到代码亲自试一试。以防请求的数据丢失,这边也单独把这个json上传,后续也可以部署在本地进行访问测试~
|
|