TextareaInputAutoHeight.tsx 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. import styleIndex from "./index.module.less";
  2. import { useState, useRef } from "react";
  3. import { countCharacters, getStrByMaxLength } from "@/utils/index";
  4. import { View, Textarea, InputProps, type TextareaProps } from "@tarojs/components";
  5. // 定义一个泛型接口来避免重复声明函数类型的返回值类型
  6. type RenderFunction = () => JSX.Element | JSX.Element[] | null;
  7. interface IProps extends Partial<Omit<TextareaProps, 'onInput' | 'onBlur' | 'onConfirm'>> {
  8. placeholder?: string;
  9. value: string;
  10. cursorSpacing?: number;
  11. maxlength?: number;
  12. disabled?: boolean;
  13. confirmType?: NonNullable<InputProps['confirmType']>; // 使用 NonNullable 防止 confirmType 被设置为 undefined
  14. extra?: RenderFunction;
  15. suffix?: RenderFunction;
  16. onInput?: (value: string) => void;
  17. onBlur?: (value: string) => void;
  18. bgColor?: string;
  19. extraClass?: string;
  20. className?: string;
  21. onConfirm?: (value: string) => void;
  22. placeholderStyle?: string;
  23. }
  24. let isInbox = false;
  25. const index = ({
  26. value,
  27. className,
  28. extraClass,
  29. disabled,
  30. confirmType,
  31. suffix,
  32. placeholder = "请输入...",
  33. onInput,
  34. onBlur,
  35. cursorSpacing,
  36. maxlength,
  37. extra,
  38. onConfirm,
  39. placeholderStyle,
  40. ...rest
  41. }: IProps) => {
  42. const [focus, setFocus] = useState(false);
  43. const inputRef = useRef<HTMLInputElement>(null); // 创建一个 ref
  44. const handleFocus = () => {
  45. isInbox = false;
  46. setFocus(true);
  47. };
  48. const handleBlur = () => {
  49. // console.log("textarea blur");
  50. if (!isInbox) {
  51. setFocus(false);
  52. if (onBlur && inputRef.current) {
  53. onBlur(inputRef.current.value);
  54. }
  55. }
  56. };
  57. const handleInput = (value: string) => {
  58. const len = countCharacters(value);
  59. if (maxlength && len > maxlength) {
  60. const r = getStrByMaxLength(value, maxlength);
  61. onInput && onInput(r);
  62. return;
  63. }
  64. onInput && onInput(value);
  65. };
  66. return (
  67. <View
  68. className={`${
  69. focus ? styleIndex.inputContainerFocused : styleIndex.inputContainer
  70. } flex items-end px-16 py-12 min-h-52 rounded-10 bg-white`}
  71. >
  72. <View className="flex items-end flex-1 w-full">
  73. <View className="min-h-24 flex items-center flex-1">
  74. <Textarea
  75. ref={inputRef}
  76. value={value}
  77. disabled={disabled}
  78. confirmType={confirmType}
  79. style={{'borderRadius': '0px', maxHeight: '120px', 'lineHeight': '24px', 'height': '24px'}}
  80. onInput={(e: any) => handleInput(e.target.value)}
  81. placeholder={placeholder}
  82. placeholderStyle={placeholderStyle ?? 'color: rgba(17,17,17,.25)'}
  83. className={`${styleIndex.textInput} ${extraClass}`}
  84. onFocus={handleFocus}
  85. onBlur={handleBlur}
  86. autoHeight
  87. maxlength={10000}
  88. onConfirm={(e: any) => {
  89. onConfirm && onConfirm(e.detail.value);
  90. }}
  91. {...rest}
  92. />
  93. </View>
  94. {suffix && suffix()}
  95. </View>
  96. </View>
  97. );
  98. };
  99. export default index;