最终效果就是实现该输入框:
- 添加话题时,话题自动插入到输入框前面
- 多文本输入框左侧间距为话题的宽度
- 多行文本时,第二行紧接开头渲染
- 删除文本时,如果删除到话题,再次删除,话题被删除
- 首先构造div结构
const [hashtag, setHashtag] = useState(""); // 话题内容const [textIndent, setTextIndent] = useState("0px"); // 动态缩进const hashtagRef = useRef(null);const [value, setValue] = useState("");const [focus, setFocus] = useState(false);<div className="topInput"><div className="topiceShow" ref={hashtagRef}>{hashtag}</div><TextAreavalue={value}onChange={(e) => setValue(e.target.value)}onInput={TextAreaInput}onFocus={() => setFocus(true)}onBlur={() => setFocus(false)}onKeyDown={handleKeyDown}autoSize={{ minRows: 3, maxRows: 5 }}maxLength={1000}style={{flex: 1,border: "none",textIndent,backgroundColor: focus ? "#ffffff" : "#f2f3f5",transition: "none",}}/></div>
2.重点是在添加话题时,获取话题的宽度和你本身需要添加的间距
const selectTopice = (item: any) => {setHashtag(`#${item.ActivityTitle}#`);setValue(` ${value}`);};
3.实时监听话题变化,给其宽度赋值
// 动态计算话题宽度useEffect(() => {if (hashtagRef.current) {const hashtagWidth = hashtagRef.current.offsetWidth;const extraPadding = 5; // 话题后的额外空隙setTextIndent(`${hashtagWidth + extraPadding}px`);}}, [hashtag]);
4.现在宽度有了,如何使其两个div并行,且第二行紧接开始呢?
这就要用到css 的样式 text-index了
text-index是 CSS 中的一个属性,用于控制文本的首行缩进。它通常用于段落、列表、文本框等元素中,指定文本的第一行相对于其容器的缩进距离。这个属性的值可以是像素(px)、百分比(%)等单位。
5.所以我们来编写样式结构
.topInput {position: relative;.topiceShow {font-size: 14px;position: absolute;left: 10px;top: 5px;z-index: 8888;display: inline-block; /* 让内容宽度适应话题文本 */}}
6.话题设置为 position: absolute;然后设置TextArea的 textIndent为计算值,即可实现这样样式格式
7.但是如何实现删除呢,这就要用到onKeyDown事件了
const handleKeyDown = (e: any) => {// 检测按键是否是 Backspace 并文本为空const cursorPosition = e.target.selectionStart;if ((e.code === "Backspace" || e.code === "Delete") &&cursorPosition === 0) {setHashtag(""); // 清空话题}};
8.至此,功能全部实现