calculateCursorPosition.js

  1. import { isArray, toString } from 'ut2';
  2. /**
  3. * 计算输入框的值格式化后光标位置
  4. *
  5. * @alias module:Other.calculateCursorPosition
  6. * @since 4.6.0
  7. * @see {@link https://2950v9.csb.app/ h5示例}
  8. * @see {@link https://33ccy9.csb.app/ react示例}
  9. * @param {number} prevPos 赋值前的光标位置,onChange/onInput的光标位置 e.target.selectionEnd
  10. * @param {string} prevCtrlValue 上一个格式化后的值
  11. * @param {string} rawValue 当前输入原值
  12. * @param {string} ctrlValue 当前格式化后的值
  13. * @param {Object} [options] 配置项
  14. * @param {string|string[]} [options.placeholderChar=' '] 占位符,默认`' '`
  15. * @param {RegExp} [options.maskReg=/\D/g] 需要遮盖的字符规则。默认`/\D/g` 去掉非数字,意味着 ctrlValue 需要去掉非数字。
  16. * @param {'mobile'|'bankCard'} [options.type] 格式化类型,内置手机号码和银行卡号特殊处理
  17. * @returns {number} 格式化后的光标位置
  18. */
  19. function calculateCursorPosition(prevPos, prevCtrlValue, rawValue, ctrlValue, options = {}) {
  20. const { placeholderChar = ' ', maskReg = /\D/g, type } = options;
  21. const realCtrlValue = toString(prevCtrlValue);
  22. const realRawValue = toString(rawValue);
  23. const placeholderChars = isArray(placeholderChar) ? placeholderChar : [placeholderChar];
  24. const editLength = realRawValue.length - realCtrlValue.length;
  25. const isAddition = editLength > 0;
  26. let pos = prevPos;
  27. if (isAddition) {
  28. const additionStr = realRawValue.substring(pos - editLength, pos);
  29. let ctrlCharCount = additionStr.replace(maskReg, '').length;
  30. pos -= editLength - ctrlCharCount;
  31. let placeholderCharCount = 0;
  32. while (ctrlCharCount > 0) {
  33. if (placeholderChars.indexOf(ctrlValue.charAt(pos - ctrlCharCount + placeholderCharCount)) !== -1) {
  34. placeholderCharCount++;
  35. }
  36. else {
  37. ctrlCharCount--;
  38. }
  39. }
  40. pos += placeholderCharCount;
  41. }
  42. if ((type === 'mobile' && (pos === 4 || pos === 9)) || (type === 'bankCard' && pos > 0 && pos % 5 === 0)) {
  43. pos -= 1;
  44. }
  45. return pos;
  46. }
  47. export default calculateCursorPosition;