背景:点击虚拟键盘上,值在输入框(Ant Design Input、或Dom inpu)中响应对应的值,支持在光标位置进行输入字符和删除等 操作,支持响应input onchange事件等功能。
实现思路:本想考虑通过物理键盘的方案进行适配,但是发现怎么都不能和物理键盘一样进行直接输入,如果有更好的方案请指教。
最后通过自定义事件来实现,实现不住如下:
1.点击虚拟键盘,发送点击按下按键的指令;
2.在项目公共地方响应指令:keyCode=6000, 6001, ..., 6009等,6000代表数字0, 以此类推6009代表数字9;
3.使用window Selection对象获取获取焦点输入框光标对象信息,从而获取:当前输入框的值,光标开始位置和结束位置等信息。根据value,selectionStart, selectionEnd, 输入值=>计算输入结果。
例如: 输入框值value=123|456,光标在3和4之间,selectionStart = 3, selectionEnd=3; 点击虚拟按键6009,即输入9。
计算公式:newValue = value.substr(0, selectionStart) + inputValue + value.substring(selectionEnd, value.length);
var newValue = '123' + 9 + '456' = '1239456'
4.值通过事件发布到当前获取焦点输入框,并触发input onChange事件:
核心:把计算结果和光标信息通过自定义事件发布到当前获取焦点的input
// 事件发布到组件中input
const evt = new UIEvent('inputchange', {
bubbles: false,
cancelable: false,
});
const keyName = 'data';
evt[keyName] = {
value: newValue,
selectionStart: selectionStart + inputValue.toString().length,
selectionEnd: selectionStart + inputValue.toString().length,
};
5.项目中封装公共的Input, 在组件中监听自定义事件,输入框在自定义事件中响应推送的值。
const inputRef = useRef<InputRef & HTMLInputElement>(null);
const inputChangeCallBack = useCallback((event: any) => {
const target = event.target;
const data = event.data;
console.info('数字键盘推送的数据', data);
if (target) {
const selectionStart = data.selectionStart || 0;
const selectionEnd = data.selectionEnd || 0;
target.value = data.value;
/**
* 响应onChange事件:解决Input, input Dom元素value值修改,在react Input获取焦点、失去焦点获取的event.target.value值是旧的,
* 原因:react input value有自己的state状态,直接修改input值,不会改变ract input中的状态。
*/
handleChange?.(event);
// 光标移动到到原来的位置加上新内容的长度
target.setSelectionRange(selectionStart, selectionEnd);
}
}, []);
/**
* 控台数字键盘-输入处理
*/
const focusInput = () => {
if (inputRef.current && inputRef.current.input) {
// react input元素
const inputNode = inputRef.current.input;
// 移除事件
inputNode.removeEventListener('inputchange', inputChangeCallBack);
// 添加添加虚拟键盘按下事件监听器
inputNode.addEventListener('inputchange', inputChangeCallBack);
// 添加添加虚拟键盘Enter监听器
inputNode.addEventListener('enter', enterCallback);
}
};
/**
* 控台数字键盘-输入处理
*/
const blurInput = () => {
if (inputRef?.current?.input) {
const inputNode = inputRef.current.input;
// 移除事件
inputNode.removeEventListener('inputchange', inputChangeCallBack);
// 移除事件
inputNode.removeEventListener('enter', enterCallback);
}
};