模拟 placeholder、空态判断、受控组件封装,React 实现 AI 编程输入框
最近看豆包的时候,发现他的代码写 AI 编程模块如下:
借助的是 contentEditable 来实现的,操作比较友好,可以随意输入可编辑数据,有类似于 placeholder 等属性。
如果我们开发大模型,免不了借鉴一下,下面基于 react 来封装一个使用 contentEditable 来实现的可编辑区域组件。
import React, { useState, useRef, useEffect } from 'react'
interface ContentEditablePromptProps {
placeholder?: string
className?: string
value?: string
onChange?: (value: string) => void
}
const ContentEditablePrompt: React.FC<ContentEditablePromptProps> = ({
placeholder = '请输入',
className = '',
value = '',
onChange
}) => {
const contentEditableRef = useRef<HTMLDivElement>(null)
const [isEmpty, setIsEmpty] = useState(true)
const [internalValue, setInternalValue] = useState(value)
useEffect(() => {
if (contentEditableRef.current) {
contentEditableRef.current.textContent = value
setIsEmpty(value.trim() === '')
}
}, [])
const updateContent = (newValue: string) => {
if (!contentEditableRef.current) return
setInternalValue(newValue)
if (onChange) {
onChange(newValue)
}
const isNowEmpty = newValue.trim() === ''
setIsEmpty(isNowEmpty)
if (isNowEmpty && contentEditableRef.current.innerHTML === '<br>') {
contentEditableRef.current.innerHTML = ''
}
}
const handleInput = () => {
if (!contentEditableRef.current) return
updateContent(contentEditableRef.current.textContent || '')
}
const handleBlur = () => {
if (!contentEditableRef.current) return
const newValue = contentEditableRef.current.textContent || ''
updateContent(newValue)
if (contentEditableRef.current.textContent !== internalValue) {
contentEditableRef.current.textContent = internalValue
}
}
useEffect(() => {
if (!contentEditableRef.current) return
if (value !== internalValue) {
setInternalValue(value)
contentEditableRef.current.textContent = value
setIsEmpty(value.trim() === '')
}
}, [value])
return (
<div
ref={contentEditableRef}
className={`p-2 px-3 w-fit rounded-2xl flex items-center ${
isEmpty
? 'after:content-[attr(data-placeholder)] after:tracking-[1px] bg-[#EEF6FF] font-bold text-[#007DFA] word-spacing-2'
: 'bg-[#EEF6FF] font-bold text-[#007DFA] word-spacing-2'
} ${className}`}
contentEditable
data-placeholder={placeholder}
onInput={handleInput}
onBlur={handleBlur}
suppressContentEditableWarning
/>
)
}
export default ContentEditablePrompt
| 要点 | 实现方式 |
|---|---|
| 模拟 placeholder | data-placeholder 存占位文案,isEmpty 时用 after 伪元素渲染 |
| 空态判断 | textContent.trim() === '' 判定为空,同步 isEmpty 状态 |
| 清空 <br> | 空内容且 innerHTML 为 <br> 时置空,避免占位样式残留 |
| 受控同步 | useEffect 监听外部 value,变化时回写 textContent 与 isEmpty |
| 失焦回滚 | handleBlur 中比较 textContent 与 internalValue,不一致时回写内部值 |
<EditableArea placeholder='预设提取项' value='' onChange={onChangeValue}></EditableArea>
以上即基于 contentEditable 的可编辑区域组件完整实现,可借鉴用于大模型产品的输入模块。