Luckysheet 远程搜索下拉 控件开发 : 揭秘二开全流程
前言
远程搜索下拉控件是非常常见的控件,应用在表单填写场景下,也是非常合适的,本例将带领大家实现以下效果,并真实了解并熟悉 luckysheet 的二开流程。
拓展单元格属性
在官网上,有一个常见问题,既然已知批注是直接加到单元格属性上,那么,我们拓展属性,是不是可以参考批注的实现方案?
我们设定以下是远程搜索下拉的单元格拓展属性:
// 扩展后的单元格对象
const cell = {
v: null, // 原始值
m: null, // 显示值
ct: { fa: "General", t: "s" },
// ... other properties
// 新增远程搜索下拉配置
remoteSelect: {
// 是否启用远程搜索,[必传]
enable: boolean,
// 用户输入时的回调函数,用于获取远程数据
onInput(value): Promise<Array<string>> {
// 这个函数需要返回一个Promise对象,resolve一个数组,数组的元素为下拉选项对象
}
// 用户选定某个选项后的回调函数
onSelect(item): void {
// item 为用户选定的选项对象,值是onInput函数返回的数组中的某个元素
}
// 是否需要设定当前输入单元格的值 [可选]
setValue(item): string{
// item 为用户选定的选项对象,需要返回一个字符串,用于设定单元格的值
},
// 自定义类名 [可选]
popperClass: string,
},
};
何时触发?
在这个场景中,我们需要在用户输入值时,进行远程数据获取,渲染列表,因此,需要在用户进行编辑时,进行处理:
- 一个方案,是在初始化 inputHTML 时,将相关事件处理:
$("body").append(inputHTML)
// 进行相关事件绑定: [伪代码]
$input.on('input',function(){
// 这里是未知具体单元格信息的,需要通过外部传递
const remoteSelectOptions = Store.flowdata[r][c]
// 执行后续操作
})
- 另一个方案,是用户双击时,唤起输入框后,进行判断:
// handler.js
$("#luckysheet-cell-main, #luckysheetTableContent").dblclick(function(){
// 这个函数是内置的哈,因此,可以直接获取到 r c
// 判断当前单元格是否需要初始化远程搜索控件
RemoteSelect.checkCellNeedRemoteSelect(row_index, col_index)
})
两种方案我都试过了,实现略有不同,但都可以实现,还是借助原生的 dblclick 好处理些。
校验远程搜索下拉
既然每一个单元格双击,都会触发这个校验,那么何时才需要初始化这个下拉框呢?
// 判断当前单元格是否需要显示下拉框
checkCellNeedRemoteSelect: function(r, c) {
// 通过 r c 获取单元格信息
let cell = Store.flowdata[r][c];
// 如果 cell 没有配置 remoteSelect 或者 remoteSelect.enable 为 false 则返回
if (!cell || !cell.remoteSelect || !cell.remoteSelect.enable) {
return;
}
}
检验完成后,如果需要初始化校验,别忘了, 我们底层还要监听输入框事件哈:
// 不然,开始监听 input 输入事件
$("#luckysheet-input-box .luckysheet-cell-input").off("input").on("input", function() {
let value = $(this).text().trim(); // 获取用户输入的值
if (cell.remoteSelect && cell.remoteSelect.onInput && typeof cell.remoteSelect.onInput == "function") {
// 调用外部接口
cell.remoteSelect
.onInput(value)
.then(function(dataList) {
$this.loading = false;
$this.showRemoteSelect(dataList);
})
.catch((error) => {
$this.loading = false;
$this.hideRemoteSelect();
console.log("请求接口错误", error);
tooltip.info('<i class="fa fa-exclamation-triangle"></i>', "接口请求失败");
});
}
});
初始化下拉框
远程搜索的核心,就是下拉选项,当远程接口初始化完成后,执行如下:
dataList.forEach((item) => {
const $item = $(`<div class="${this.selectItemClass}">`)
.text(item)
.click(() => {
// 触发选择回调
if (cell.remoteSelect && cell.remoteSelect.onSelect && typeof cell.remoteSelect.onSelect === "function") {
cell.remoteSelect.onSelect(item);
}
})
这里就一个难点要处理,如何将下拉框定位到输入框的位置:
// 这里采用巧方案,直接取输入框的位置
const $input = $("#luckysheet-input-box");
const left = parseInt($input.css("left")) || 0;
const top = parseInt($input.css("top")) || 0;
// 获取当前单元格的高度 行高
const [_row_pre, rowHeight] = rowLocation(this.r);
// 设置下拉框位置和宽度
$selectBox.css({
top: `${top + rowHeight + 4}px`, // 在单元格下方显示
left: `${left}px`,
});
总结
虽然代码看起来不复杂,但是了解luckysheet 的源码、实现思路,以及单元格拓展实现方案是非常重要的。
通过本次实现,我们初步了解了luckysheet的二次开发流程,在不破坏原有功能的基础上添加新特性。远程搜索下拉控件的实现展示了如何在现有表格组件基础上,通过合理的架构设计和代码组织,添加复杂交互功能。