如果字体是等宽字体,则使用ch 单位会起作用,否则字符宽度会发生变化。我会通过渲染一个包含相同文本的内联元素来解决这个问题,每次输入字段值发生变化时测量它并立即隐藏它。
为此,最好创建一个单独的组件来渲染句子,我们称之为Sentence:
const Test = () => {
return (
<div className="App">
{value.map(({ sentence }, i) => {
return (
<Sentence
initialValue={sentence}
key={i}
/>
);
})}
</div>
);
};
Test 将传递初始值,然后Sentence 将继续保持自己的状态:
const Sentence = ({ initialValue }) => {
const [value, setValue] = React.useState(initialValue)
return (
<SentenceInput
type="text"
value={value}
onChange={(event) => {
setValue(event.target.value)
}}
/>
)
}
接下来,我将添加一个span 元素,该元素将用作测量器元素,其中文本的样式应与输入元素中的样式相同,因此测量结果准确。在 Chrome 中的示例中,这意味着将字体大小设置为 13.3333px。
现在最棘手的部分是,我们需要结合useEffect 和useLayoutEffect; useEffect 将使测量器可见,然后useLayoutEffect 将测量并隐藏它
这是结果:
const Sentence = ({ initialValue }) => {
const [value, setValue] = React.useState(initialValue)
const [visible, setVisible] = React.useState(false)
const [width, setWidth] = React.useState('auto')
const measurer = React.useRef(null)
React.useEffect(() => {
setVisible(true)
}, [value])
React.useLayoutEffect(() => {
if (visible) {
const rect = measurer.current.getBoundingClientRect()
setWidth(rect.width)
setVisible(false)
}
}, [visible])
return (
<>
<span
ref={measurer}
style={{ fontSize: '13.3333px' }}
>
{visible && value}
</span>
<SentenceInput
type="text"
value={value}
style={{ width: width + 1 }}
onChange={(event) => {
setValue(event.target.value)
}}
/>
</>
)
}
我将1px 添加到计算的width 中,因为它似乎删除了输入字段中的一个小的水平滚动。
这是为了让您以您想要的方式进一步调整,例如当它达到视口宽度时应该如何表现。