MUI TextField标签与浏览器自动填充值重叠的UI问题求助
MUI TextField浏览器自动填充时标签重叠问题解决
这个问题的核心原因是:浏览器自动填充表单时会直接修改DOM输入框的值,但不会触发React的onChange事件,导致react-hook-form的内部状态没有同步更新。MUI的TextField浮动标签(Floating Label)依赖表单状态判断是否上浮,所以初始加载时标签和填充内容重叠;点击页面后触发了组件重渲染或状态同步,标签才恢复正常。
下面是可行的解决方法及代码修正:
方法1:通过inputRef手动同步自动填充值
在Controller渲染TextField时,利用inputRef检测输入框实际值,若浏览器已填充但form状态未更新,则手动触发onChange同步状态:
import * as React from "react"; import Avatar from "@mui/material/Avatar"; import Button from "@mui/material/Button"; import TextField from "@mui/material/TextField"; import Box from "@mui/material/Box"; import LockOutlinedIcon from "@mui/icons-material/LockOutlined"; import Typography from "@mui/material/Typography"; import Container from "@mui/material/Container"; import { Paper } from "@mui/material"; import { Controller, useForm } from "react-hook-form"; import * as yup from "yup"; import { yupResolver } from "@hookform/resolvers/yup"; export function LoginPage() { const schema = yup.object().shape({ trigram: yup.string().max(3).min(3).required("Trigramme est requis"), password: yup.string().required("Mot de passe est requis"), }); const { handleSubmit, control, formState: { errors }, } = useForm({ resolver: yupResolver(schema), defaultValues: { trigram: "", password: "", }, }); const onSubmit = (data) => { console.log("submit", data); }; return ( <Container component="main" maxWidth="xs"> <Paper elevation={2} sx={{ p: 4, }} > <Box sx={{ display: "flex", flexDirection: "column", alignItems: "center", }} > <Avatar sx={{ m: 1, bgcolor: "primary.main" }}> <LockOutlinedIcon /> </Avatar> <Typography component="h1" variant="h5"> Connexion </Typography> <Box component="form" onSubmit={handleSubmit(onSubmit)} noValidate sx={{ mt: 1 }} > <Controller name="trigram" control={control} render={({ field, fieldState }) => ( <TextField {...field} inputRef={(el) => { field.ref(el); // 检测浏览器自动填充的值并同步到form状态 if (el && el.value && !fieldState.value) { field.onChange(el.value); } }} margin="normal" error={!!errors.trigram} helperText={errors.trigram?.message} required fullWidth label="Trigramme" autoComplete="username" autoFocus /> )} /> <Controller name="password" control={control} render={({ field, fieldState }) => ( <TextField {...field} inputRef={(el) => { field.ref(el); if (el && el.value && !fieldState.value) { field.onChange(el.value); } }} margin="normal" error={!!errors.password} helperText={errors.password?.message} required fullWidth label="Mot de passe" autoComplete="current-password" type="password" /> )} /> <Button type="submit" fullWidth variant="contained" sx={{ mt: 3, mb: 2 }} > Connexion </Button> </Box> </Box> </Paper> </Container> ); }
方法2:使用useEffect挂载后同步DOM值
从useForm中解构出setValue,在组件挂载后检测输入框实际值并同步到form状态:
// 在useForm解构中添加setValue const { handleSubmit, control, setValue, formState: { errors }, } = useForm({...}); // 添加useEffect React.useEffect(() => { setTimeout(() => { const trigramInput = document.querySelector('input[autocomplete="username"]'); const passwordInput = document.querySelector('input[autocomplete="current-password"]'); if (trigramInput?.value) { setValue('trigram', trigramInput.value); } if (passwordInput?.value) { setValue('password', passwordInput.value); } }, 100); }, [setValue]);
额外修正:原代码错误提示bug
你原代码中两个TextField的error和helperText错误引用了errors.email,但实际字段名是trigram和password,这会导致错误提示无法正常显示,上面的修正代码已修复该问题。
内容的提问来源于stack exchange,提问作者Enzo
相关产品推荐
相关产品推荐

