React - contentEditable属性的onChange事件

10
我希望使用类似于

请查看此链接:https://dev59.com/VWEh5IYBdhLWcg3wNxEn - Mayank Pandeyz
为什么不使用输入标签? - Michael
5个回答

3
我的建议是使用onInput,但是不要将状态变量作为可编辑元素的innerHTML。
设置一些默认值,contentEditable将处理innerHTML的更改,而onInput将处理状态从innerHTML的值的更改。
如果您想确保innerHTML不为空,可以添加onBlur事件,检查它是否=== "",并将其更新为默认值或其他内容等。

4
我不理解你的回答 @Dimitar - Sarah
我的意思是,contentEditable 显示默认值,如果你输入一些内容,即使没有 onInput 事件它也会显示更改。但是,如果你需要处理状态中值的更改,那么你需要使用 onInput,这里的问题是在每个输入字符时它将光标移动到字符串值的开头(可能使用一些延迟定时器会更合理)。我不知道你为什么需要它,但我更喜欢使用 <input/> 和 onChange 事件。 - Dimitar Daskalov

1

这个问题很老了,但我刚刚为自己解决了它,所以想分享一下。

onChange 永远不会触发,onInput 也不是最好的方法。你需要用 onFocus 和 onBlur 来模拟 onChange。

当 onFocus 发生时,将 innerHTML 的值复制到一个变量中。

当 onBlur 发生时,将 innerHTML 与该变量进行比较,看是否有更改。如果有更改,则执行 onChange 相关操作。你需要像这样:

  const onFocus = (e) => {
    val_start = e.target.innerHTML;
  };
  const onBlur = (e) => {
    if(val_start !== e.target.innerHTML) {
      //Whatever you put here will act just like an onChange event
      const html = e.target.innerHTML;
      setValue(html);
    }
  };

1

contentEditable 可以使 div 内容可编辑。

你可以使用 onBlur 而不是 onInput,这样闪烁的光标就不会不停地移动到文本开头。

无论你对文本做出什么更改,都将在屏幕上显示,并且一旦你将焦点移出元素,状态就会更新。

<div onBlur={onChange} contentEditable>
  {value}
</div>

非常感谢你,这个答案非常好,谢谢!它有效果! - undefined

1

使用React Hook Form 2023的Typescript实现。

简短总结:以下是完整代码,适合那些匆忙的人。

注意:下面的代码是一个简化版本,原本是一个更长的代码片段,其中使用了zod。为了简单起见,我删除了一些部分。

export const EmailForm: React.FC = () => {
    const {register, handleSubmit, formState: {errors}, setValue} = useForm();

    // Optional: for when the <label> gets clicked
    const emailRef = useRef<HTMLDivElement>(null);

    const onSubmit = async (data: FieldValues) => {
        // Send data here. In catch statement use setError or formError
        console.log(data);
    }

    const onInput = (e: FormEvent<HTMLInputElement>) => {
        setValue('email', e.currentTarget.innerText);
    }

    return (
        <form onSubmit={handleSubmit(onSubmit)}>
            {/* The actual field which react hook form validates */}
            <input type="hidden" {...register('email')} />

            <div>
                <label onClick={() => emailRef.current?.focus()}>Email</label>
                <div contentEditable onInput={onInput} ref={emailRef}
                     role="textbox" tabIndex={0}></div>
                <div>{errors.email?.message}</div>
            </div>
            <div>
                <button type="submit">Submit</button>
            </div>
        </form>
    );
}

基本上,你想要的是让 div 元素在保持功能的同时,像一个 <textarea> 一样工作。这样做的好处各有不同,但通常我会让它在用户输入时自动扩展。

使用 React Hook Form 进行注册

由于这是 React,我使用 RHF 来管理内容,所以我们需要在用户输入时填充一个隐藏字段。这个字段也可以是一个 <textarea>,但请确保它是不可见的。

<input type="hidden" {...register('email')} />

处理数据
对于一个
标签来说,它并不知道什么是事件,但是它对事件有很好的响应,所以请使用它。此外,还可以添加和属性来提高可用性,具体请参考这个链接
<label onClick={() => emailRef.current?.focus()}>Email</label>
<div contentEditable onInput={onInput} ref={emailRef}
     role="textbox" tabIndex={0}></div>

如果你想让 <label> 在点击时像标签一样聚焦在 <div> 上,你可以选择使用 useRef 来实现这个功能。
const emailRef = useRef<HTMLDivElement>(null);

有了onInput={onInput}回调函数,现在每当用户输入内容时,setValue函数就会被调用,使得RHF可以像处理其他字段一样访问数据。这进而有助于生成错误信息。
<div>{errors.email?.message}</div>

最后,当表单被提交时,将触发onSubmit回调函数。从那里,您可以将其发送到您的服务器。

-1

不客气。您可以接受或点赞这个答案! - Sakshi
7
@Sakshi 在 ReactJS 的 contentEditable div 中,onChange 不起作用。 - Umang
成功了!这是你需要的:<div onChange={onChange} contentEditable> 应该使用onChange而不是onInput - Shapon Pal
9
对我而言,onChange 不起作用。对我有用的是:onInput((e) => console.log(e.target.innerText))。 - Gijs van Beusekom
这不起作用。 - Sarah

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接