自定义单元格实现查询下拉(AutoComplete)
本帖最后由 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.style.width = "100%";
editor.children.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上绘制的形式。
AutoCompleteCellType.prototype.paint = function (ctx,value,x,y,w,h,style,options) {
if (value) {
GC.Spread.Sheets.CellTypes.Base.prototype.paint.apply(this, );
}
};
再下来就是触发编辑器的方法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.id,
value: data.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上传,后续也可以部署在本地进行访问测试~
页:
[1]