我正在 React 中构建这个自定义 Textarea 组件,它将显示在 Storybook 中。 不知何故,我无法使其与该组件的 maxLength 道具一起使用,因为我可以编写一个在设置道具时超出 maxLength 的用户输入。即使我将 maxLength 硬编码为例如 10,我仍然可以超过该 maxLength。
这是我的组件代码:
import { FormControl, FormHelperText, Grid, Textarea, TextareaProps, Typography } from "@mui/joy";
import Image from "next/image";
import errorhelper from "../../../public/errorhelper.svg";
import search from "../../../public/search.svg";
import { InnerTextarea } from "./styles/TextAreaStyles";
type TextAreaBaseProps = Pick<TextareaProps, "disabled" | "error" | "value" | "onChange"> & {
/**If true the icon is shown in the start of the textfield */
showIcon: boolean;
/**If true the textfield is optional */
optional: boolean;
/**Shows the textfield in focus state */
focus?: boolean;
/**The helper text for input field in default state*/
helperText?: string;
/**The helper text for input field in error state */
errorHelperText?: string;
/**The label for the input field */
label: string;
/**The maximum length of the inputfield */
maxLength?: number;
};
/** A custom textarea component using Joy-UI's Textarea */
export const TextAreaField = ({
showIcon,
optional,
focus,
helperText,
errorHelperText,
label,
maxLength,
...props
}: TextAreaBaseProps) => {
return (
<FormControl>
<Textarea
{...props}
minRows={6}
sx={{
display: "flex",
width: "19.125rem",
...(focus && {
outline: "0.125rem solid var(--colorSystemColorsFocus500)",
outlineOffset: "-0.0625rem"
}),
"& .css-1p7e9sy-JoyTextarea-startDecorator": {
marginBlockEnd: 0
}
}}
startDecorator={
<Grid container direction={"row"} justifyContent={"space-between"} width={"19.125rem"}>
<Grid marginTop={0.5}>{showIcon && <Image src={search} alt={""} width={16} height={16} />}</Grid>
<Grid>
{optional && (
<Typography sx={{ ml: 1, color: "var(--colorTextDefault)" }}>(Optional)</Typography>
)}
</Grid>
</Grid>
}
slotProps={{
textarea: {
...(maxLength && { maxLength })
}
}}
slots={{
textarea: () => <InnerTextarea {...props} showIcon={showIcon} label={label} />
}}
/>
<Grid container direction={"row"} justifyContent={"space-between"} width={"19.125rem"}>
<Grid>
{props.error ? (
<FormHelperText sx={{ color: "var(--colorSystemColorsDanger500)" }}>
<Image src={errorhelper} alt={""} width={16} height={16} /> {errorHelperText}
</FormHelperText>
) : (
helperText && <FormHelperText>{helperText}</FormHelperText>
)}
</Grid>
<Grid>
{maxLength && (
<FormHelperText>
{props.value?.toString().length}/{maxLength}
</FormHelperText>
)}
</Grid>
</Grid>
</FormControl>
);
};
这是添加到组件中的一些样式,取自此处:https://mui.com/joy-ui/react-textarea/#floating-label
import { styled } from "@mui/joy";
import { TextareaAutosize } from "@mui/base/TextareaAutosize";
import React from "react";
const StyledTextarea = styled(TextareaAutosize)({
resize: "none",
border: "none", // remove the native textarea border
minWidth: 0, // remove the native textarea width
outline: 0, // remove the native textarea outline
padding: 0, // remove the native textarea padding
paddingBlockStart: 0,
paddingInlineEnd: 0,
flex: "auto",
alignSelf: "stretch",
color: "inherit",
backgroundColor: "transparent",
fontFamily: "inherit",
fontSize: "inherit",
fontStyle: "inherit",
fontWeight: "inherit",
lineHeight: "inherit",
"&::placeholder": {
opacity: 0,
transition: "0.1s ease-out"
},
"&:focus::placeholder": {
opacity: 1
}
});
const StyledLabel = styled("label")(({ theme }) => ({
position: "absolute",
lineHeight: 1,
top: "calc((var(--Textarea-minHeight) - 1em) / 2)",
color: "var(--colorTextSubtle1)",
transition: "all 150ms cubic-bezier(0.4, 0, 0.2, 1)"
}));
export const InnerTextarea = React.forwardRef<
HTMLTextAreaElement,
React.JSX.IntrinsicElements["textarea"] & { showIcon: boolean; label: string }
>(function InnerTextarea({ showIcon, label, ...props }, ref) {
const id = React.useId();
console.log(props.value);
return (
<React.Fragment>
<StyledTextarea minRows={2} {...props} ref={ref} id={id} />
<StyledLabel
sx={{
marginLeft: showIcon ? "1rem" : 0,
fontSize: props.value ? "0.75rem" : "1rem",
top: props.value ? "0.5rem" : null
}}
htmlFor={id}>
{label}
</StyledLabel>
</React.Fragment>
);
});
您需要通过检查
onChange
功能并检查长度是否小于允许的最大长度来限制用户输入。像这样的事情:-
<StyledTextarea minRows={2} {...props} ref={ref} id={id} onChange={(e) => { if(e.target.value.length > 10) { setValue(e.target.value)}}}/>