Taro 小程序的InputNumber组件

443 阅读1分钟

在使用taro开发小程序过程中,发现taro-ui 的 InputNumber 组件在小程序设置了最小值后,无法删除最小值,只能输入以最小值为起始的值,遂自己开发一个这样的组件来使用
上代码~

import { Input, View, Image } from "@tarojs/components";
import React from "react";
import Taro from "@tarojs/taro";
import classnames from "classnames";
// @ts-ignore
import plusSvg from "@/public/images/product/plus.svg";
// @ts-ignore
import MinuteSvg from "@/public/images/product/minute.svg";
// @ts-ignore
import MinuteDisableSvg from "@/public/images/product/minute-disabled.svg";

import "./index.scss";

export default function InputNumberCom(props) {
  const { disabled, min, max, showToast = true } = props;

  const addNum = (num1, num2) => {
    let sq1, sq2, m;
    try {
      sq1 = num1.toString().split(".")[1].length;
    } catch (e) {
      sq1 = 0;
    }
    try {
      sq2 = num2.toString().split(".")[1].length;
    } catch (e) {
      sq2 = 0;
    }
    m = Math.pow(10, Math.max(sq1, sq2));
    return (Math.round(num1 * m) + Math.round(num2 * m)) / m;
  };

  const handleChangeStep = (type) => {
    const { step = 1 } = props;
    let { value } = props;

    if (!value || Number.isNaN(+value)) {
      value = min;
    }

    if (disabled) return null;

    if (type === "minus") {
      value = addNum(value, -step);
    } else if (type === "plus") {
      value = addNum(value, step);
    }
    console.log({ value, min, max }, "---handleChangeStep---");
    showMaxToast(value);
    if (value < min || value > max) return null;

    handleEmit(value, type);
  };

  const handleMinus = () => {
    props.value > min && handleChangeStep("minus");
  };

  const handlePlus = () => {
    handleChangeStep("plus");
  };

  const showMaxToast = (value) => {
    if (showToast && value > max) {
      Taro.showToast({
        icon: "none",
        title: `最多只能买${max}件哦~`,
      });
    }
  };
  const handleValue = (e, type?: string) => {
    let { value } = e.detail;
    if (!value) {
      if (type === "blur") {
        setTimeout(() => {
          handleEmit(min);
        }, 10);
      }
      return;
    }
    value = +value;
    showMaxToast(value);
    if (value > max) {
      value = max;
    } else if (value < min) {
      value = min;
    }
    return value;
  };

  const handleBlur = (e, type) => {
    const value = handleValue(e, type);
    handleEmit(value);
  };

  const handleEmit = (val, type?: string) => {
    const data: any = {
      value: val,
    };
    if (type) data.type = type;
    props.onChange(data);
  };

  return (
    <View className="input-number-com">
      <View
        className={classnames("input-number-com__minute", {
          disabled: props.value <= min,
        })}
        onClick={handleMinus}
      >
        <Image src={props.value <= min ? MinuteDisableSvg : MinuteSvg} />
      </View>
      <Input
        value={props.value}
        disabled={disabled}
        className="input-number-com__input"
        type="number"
        cursor={-1}
        onBlur={(e) => handleBlur(e, "blur")}
        onInput={(e) => handleBlur(e, "input")}
      />
      <View
        className={classnames("input-number-com__plus", {
          disabled: props.value >= max,
        })}
        onClick={handlePlus}
      >
        <Image src={plusSvg} />
      </View>
    </View>
  );
}

顺便贴上样式文件吧

.input-number-com {
  display: flex;
  align-items: center;
  &__minute,
  &__plus {
    font-size: 24px;
    padding: 16px;
    image {
      width: 16px;
      height: 16px;
      object-fit: contain;
    }
  }

  .disabled {
    color: #f2f2f2;
  }
  &__input {
    background: #f2f2f2;
    border-radius: 2px;
    height: 36px;
    width: 64px;
    border-left: none;
    border-right: none;
    font-size: 24px;
    text-align: center;
  }
}

共勉之~