Android Tabulator下拉框键盘消失问题解决方案
2025-03-04 11:35:39
Android 上 Tabulator 下拉编辑器字段键盘消失问题
碰到了一个棘手的问题:在 Android 设备上,特别是三星平板(Android 13),使用 Tabulator 的下拉列表编辑器时,键盘老是自动消失。看样子是键盘弹出导致表格重绘(table.redraw()
),编辑器因此失去焦点,键盘也就跟着消失了。 GIF 动图清晰地展示了这一现象。
问题原因深究
经过一番探查和比对,找到了几个关键点:
- 问题复现环境: 这个问题主要出现在基于 Chromium 的浏览器中,如 Chrome 和 Edge。在 Firefox 中则没有这个问题。
- IFRAME 环境: 在 JSFiddle 或类似的代码片段环境(它们通常运行在 IFRAME 中)中,问题不会出现。这暗示了 IFRAME 可能避免了某种重绘或尺寸调整。
- resize 事件: 推测 Android 键盘的弹出触发了
resize
事件,可能影响了 Tabulator 表格。Tabulator 为了响应布局变化,进行了重绘,导致正在编辑的下拉列表失去焦点。
解决方案大集合
针对以上分析,可以尝试以下几种解决方案,从简单到复杂,逐步排查。
1. 禁用表格自动调整 ( redraw
)
最直接的方法是尝试阻止 Tabulator 在 resize
事件发生时自动重绘。 虽然可能有效,但会影响用户体验。
原理: Tabulator 默认会在窗口大小变化时自动调整布局。禁用这个功能可以避免键盘弹出导致的重绘。
代码示例:
// 创建 Tabulator 实例时,设置 autoResize 为 false
var table = new Tabulator("#example-table", {
height: "311px",
data:data,
autoResize: false, // 禁用自动调整
columns: [
{
title: "Location",
field: "location",
width: 130,
editor: "list",
editorParams: {
autocomplete: "true",
allowEmpty: true,
listOnEmpty: true,
valuesLookup: true
}
},
],
});
缺点:
禁用自动调整会让表格大小变得固定,不会自适应不同的手机型号与屏幕。
2. 延迟编辑器激活
让编辑器在获得焦点之后稍微等一下, 也许能规避键盘和重绘的冲突。
原理: 给编辑器的激活留出一点缓冲时间,让键盘完全弹出,避免后续的布局变化。
代码示例:
var table = new Tabulator("#example-table", {
height: "311px",
data:data,
columns: [
{
title: "Location",
field: "location",
width: 130,
editor: "list",
editorParams: {
autocomplete: "true",
allowEmpty: true,
listOnEmpty: true,
valuesLookup: true
},
cellEditing:function(cell){
setTimeout(function(){
cell.getElement().querySelector("input, select").focus();
}, 100); // 延迟 100 毫秒
}
},
],
});
补充说明: 上面例子直接修改 cellEditing
方法可能会破坏默认编辑逻辑, 使用前需谨慎或只用于测试.
3. 监听 focusout
事件 (失去焦点)
捕获编辑器的 focusout
事件, 确认失焦是预期内的再进行刷新。
原理: focusout
事件会在元素失去焦点时触发。我们可以检查是否真的是用户主动移开了焦点,而不是键盘导致的。
代码示例:
var table = new Tabulator("#example-table", {
height: "311px",
data:data,
columns: [
{
title: "Location",
field: "location",
width: 130,
editor: "list",
editorParams: {
autocomplete: "true",
allowEmpty: true,
listOnEmpty: true,
valuesLookup: true,
elementAttributes:{
//防止失焦时 redraw 整个 table
onfocusout:"event.stopPropagation();"
}
}
},
],
});
补充说明: 上面使用的 elementAttributes
参数直接给 input 加入了 onfocusout
属性.
4. CSS 方案:固定容器高度
如果 Tabulator 表格外层有一个可滚动的容器,可以尝试固定容器高度,防止键盘影响布局。
原理: 键盘弹出通常会挤压页面内容。如果外层容器高度固定,键盘就不会影响到 Tabulator 表格。
操作步骤:
- 找到 Tabulator 表格的父容器(或祖先容器),这个容器通常会有滚动条。
- 使用 CSS 设置该容器的
height
为一个固定值(例如,500px
)。 也可以考虑设max-height
. - 确保
overflow: auto
或overflow: scroll
,以保证内容超出时出现滚动条。
CSS 示例:
#parent-container { /* 假设这是父容器的 ID */
height: 500px;
overflow: auto;
}
补充说明: 这个固定值并非完美解决所有情况, 需要手动调到最合适的值.
5. 自定义编辑器 (终极方案)
以上都解决不了, 那就手动处理输入和选择。
原理: 完全接管编辑器的行为,不依赖 Tabulator 的默认编辑器逻辑,可以最大程度地控制键盘和焦点。
实现步骤(大致思路,非完整代码):
editor: "input"
(或自定义函数): 设置一个简单的文本输入框作为编辑器,或者提供一个自定义编辑器函数。- 手动显示选项:
- 监听输入框的
click
或focus
事件。 - 在事件处理函数中,动态创建一个包含选项的
div
或其他元素。 - 将这个
div
定位到输入框下方(或其他合适位置)。
- 监听输入框的
- 处理选择:
- 监听选项
div
中每个选项的click
事件。 - 在事件处理函数中,获取选中值,更新 Tabulator 单元格的值。
- 隐藏选项
div
。
- 监听选项
- 处理输入(可选): 如果需要实时过滤选项,监听输入框的
input
事件,根据输入内容更新选项div
。
代码示例 (只提供简单的结构, 非完整功能):
function customListEditor(cell, onRendered, success, cancel, editorParams){
//cell - the cell component for the editable cell
//onRendered - function to call when the editor has been rendered
//success - function to call to pass the successfuly updated value to Tabulator
//cancel - function to call to abort the edit and return to a normal cell
//editorParams - params object passed into the editorParams column definition property
//create and style input
var input = document.createElement("input");
input.setAttribute("type", "text");
//create custom এইসব for the editor
//... 创建用于显示列表的 div 等等
var optionsContainer = document.createElement("div");
//赋值给 editorParams 方便后续从 cell 中读取.
editorParams.optionsContainer = optionsContainer
//... 将输入与 optionsContainer 连结起来
input.addEventListener("focus", function(e){
//从资料库里获取数值的逻辑...
values = ["United Kingdom","Germany"];
optionsContainer.innerHTML = ""; // 清空之前的选项
values.forEach(value=>{
//建立给用户选的 element
const optionElement = document.createElement("div");
optionElement.textContent = value;
//用户选择了值之后的更新操作
optionElement.addEventListener("click", function(){
success(value); //更新数值
optionsContainer.style.display = "none"; //关闭选单
});
optionsContainer.appendChild(optionElement)
})
});
//...
//input.value = cell.getValue();
//input.style.padding = "4px";
//input.style.width = "100%";
//input.style.boxSizing = "border-box";
//...
onRendered(function(){
input.focus();
//input.style.height = "100%";
});
function onChange(){
success(input.value);
}
//submit new value on blur or change
//input.addEventListener("change", onChange); //失去焦点更新
//input.addEventListener("blur", onChange); //按下 Enter 更新
//return the editor element
return input;
};
var table = new Tabulator("#example-table", {
height: "311px",
data:data,
columns: [
{
title: "Location",
field: "location",
width: 130,
editor: customListEditor,
},
],
});
进阶:
可以使用一些前端UI控件库提供的, 能够良好处理移动端输入问题的输入选择框. 比如 select2
只需要在上述 customListEditor
中使用 UI 控件生成组件即可。
安全建议
上面方法主要关注解决显示问题, 安全方面一般不需要考虑. 如果有特殊数据, 对用户输入做好校验与转义永远是好的。