Sin descripción

index.tsx 4.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. import React, { useState } from "react";
  2. import classnames from "classnames";
  3. import { Input } from "antd";
  4. import styles from "./PriceOptions.less";
  5. import { exportStyleSizeClass } from '../Utils/utils';
  6. /**
  7. * rowModa: "single" 单行 | "multi" 两行
  8. * price:number 金额
  9. * onPriceChange: (value: price) => void
  10. * size: "small" | "normal" | "large" 样式暂无支持
  11. * focusScroll:boolean 点击时是否自动滚动到输入框处
  12. * withTitle:boolean 是否显示标题
  13. * titleText:string|dom 标题内容
  14. * inputPlaceholderText:string 输入框默认内容
  15. * priceOptions:Array 金额按钮数组,默认为 [100, 600, 800]
  16. * priceRender:Function 金额按钮内部数字渲染字样
  17. * inputPriceRender:Function 输入框金额字体渲染字样
  18. * inputSuffix:string|dom Antd组件Suffix属性
  19. * injectOptions: { priceBtnClass, priceInputClass } 分别控制具体渲染按钮和输入框样式
  20. * inputRef:React.RefObject<any> Input的Ref
  21. * @interface Props
  22. */
  23. interface Props {
  24. rowMode: "single" | "multi";
  25. price: number;
  26. onPriceChange: (v: number) => void;
  27. size: "small" | "normal" | "large";
  28. focusScroll: boolean;
  29. withTitle: boolean;
  30. allowZero: boolean;
  31. titleText?: string | JSX.Element[] | JSX.Element;
  32. inputPlaceholderText?: string;
  33. priceOptions?: Array<any>;
  34. priceRender?: Function;
  35. inputPriceRender?: Function;
  36. inputSuffix?: string | JSX.Element[] | JSX.Element;
  37. injectOptions?: {
  38. priceBtnClass: (isActive: boolean) => any;
  39. priceInputClass: Function;
  40. }
  41. inputRef: React.RefObject<any>;
  42. }
  43. const PriceOptions = ({
  44. price,
  45. onPriceChange,
  46. allowZero,
  47. rowMode = "single",
  48. size = "normal",
  49. focusScroll = true,
  50. withTitle = true,
  51. titleText = "Price",
  52. inputPlaceholderText = "Others",
  53. priceOptions = [100, 600, 800],
  54. priceRender = (i: any) => i / 100,
  55. inputPriceRender = (i: any) => (i ? i / 100 : ""),
  56. inputSuffix = "¥",
  57. injectOptions = {
  58. priceBtnClass: () => undefined,
  59. priceInputClass: () => undefined,
  60. },
  61. inputRef
  62. }: Props) => {
  63. const defaultOptions = priceOptions;
  64. // 控制是否为其他金额输入情况
  65. const [inputStatus, setInputStatus] = useState(false);
  66. const [inputPrice, setInputPrice] = useState('');
  67. return (
  68. <div className={classnames(styles.options, {
  69. [styles.multi]: rowMode === "multi",
  70. ...exportStyleSizeClass(styles, size),
  71. })}>
  72. {withTitle ? (titleText || null) : null}
  73. <div className={styles.infoItem}>
  74. <span className={styles.priceBtn}>
  75. {defaultOptions.map(item => {
  76. const isActive = price === item && !inputStatus;
  77. return (
  78. <span
  79. className={classnames({
  80. [styles.priceItem]: true,
  81. [styles.active]: !injectOptions.priceBtnClass(isActive) && isActive,
  82. ...injectOptions.priceBtnClass(isActive),
  83. })}
  84. key={item}
  85. onClick={() => {
  86. onPriceChange(item);
  87. setInputStatus(false);
  88. }}
  89. >
  90. {priceRender(item)}
  91. </span>
  92. );
  93. })}
  94. </span>
  95. <Input
  96. ref={inputRef}
  97. className={classnames(styles.priceInput, {...injectOptions.priceInputClass()})}
  98. onMouseEnter={() => {
  99. if (inputStatus && inputRef && inputRef.current) {
  100. inputRef.current.focus();
  101. inputRef.current.select();
  102. }
  103. }}
  104. suffix={inputSuffix}
  105. value={inputStatus ? inputPriceRender(inputPrice) : ""}
  106. placeholder={inputPlaceholderText}
  107. onChange={e => {
  108. const n = +e.target.value;
  109. if (Number.isNaN(n)) {
  110. return;
  111. }
  112. if (!allowZero && n === 0) {
  113. return;
  114. }
  115. // 测试暂时改成1分
  116. setInputPrice(`${n * 100}`);
  117. onPriceChange(n * 100);
  118. }}
  119. onClick={e => {
  120. if (!inputStatus) {
  121. setInputPrice('');
  122. setInputStatus(true);
  123. }
  124. }}
  125. onFocus={e => {
  126. e.target.placeholder = "";
  127. if (inputStatus) {
  128. setInputPrice(`${price}`);
  129. } else {
  130. setInputPrice('');
  131. setInputStatus(true);
  132. }
  133. if (focusScroll) {
  134. e.target.scrollIntoView();
  135. }
  136. }}
  137. onBlur={e => {
  138. e.target.placeholder = inputPlaceholderText;
  139. if (inputPrice) {
  140. setInputStatus(true);
  141. } else {
  142. setInputStatus(false);
  143. }
  144. }}
  145. />
  146. </div>
  147. </div>
  148. );
  149. };
  150. export default PriceOptions;