在 React 中将输入自动缩放到值的宽度
Auto-scaling input to width of value in React
我想要一个宽度适应其内容的输入。
我正在尝试实施 this answer to a similar question,但使用的是 React:
import React, { useState } from 'react';
export default () => {
const [content, setContent] = useState('');
const [width, setWidth] = useState(0);
const changeHandler = evt => {
setContent(evt.target.value);
};
return (
<wrapper>
<span id="hide">{content}</span>
<input type="text" autoFocus style={{ width }} onChange={changeHandler} />
</wrapper>
);
};
问题是我不知道如何查询跨度的宽度,以便随后更改输入的宽度(使用 setWidth
)。
我怎样才能做到这一点?
嗯,这已经足够有趣了!
我尝试了几个不同的想法,但 none 中的想法完美运行 - 特别是如果它们是用稍微体面的代码编写的。
不过我发现了这个 post 并决定尝试一下。
我敢肯定它有缺陷,例如,除非我使用等宽字体,否则它确实很有趣。但也许有一些 css 技巧可以解决这个问题?
// Normally I'd go for ES6 imports, but to make it run as a Whosebug snippet I had to do it this way
const { useState, useRef } = React;
const GrowingInput = () => {
const [width, setWidth] = useState(0);
const changeHandler = evt => {
setWidth(evt.target.value.length);
};
return (
<input style={{ width: width +'ch'}} type="text" autoFocus onChange={changeHandler} />
)
};
const App = () => {
return (
<p>Lorem ipsum {<GrowingInput />} egestas arcu.</p>
);
};
// Render it
ReactDOM.render(<App />, document.getElementById("react"));
input {
font-family: Courier;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
您是否考虑过使用 contenteditable
?
https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Editable_content
折腾了很久,终于找到解决办法了!
import React, { useState, useRef, useEffect } from 'react';
export default () => {
const [content, setContent] = useState('');
const [width, setWidth] = useState(0);
const span = useRef();
useEffect(() => {
setWidth(span.current.offsetWidth);
}, [content]);
const changeHandler = evt => {
setContent(evt.target.value);
};
return (
<wrapper>
<span id="hide" ref={span}>{content}</span>
<input type="text" style={{ width }} autoFocus onChange={changeHandler} />
</wrapper>
);
};
为了获得对 #hide
跨度的引用,我使用了 useRef
。然后,width
状态变量可以通过 useEffect
中定义的函数更新,每次 content
更改时都会调用该函数。
我还必须将 #hide
的 css 中的 display: none
切换为 position: absolute
和 opacity: 0
,否则 targetRef.current.offsetWidth
会始终为 0。
这里是a working demo。
我想要一个宽度适应其内容的输入。
我正在尝试实施 this answer to a similar question,但使用的是 React:
import React, { useState } from 'react';
export default () => {
const [content, setContent] = useState('');
const [width, setWidth] = useState(0);
const changeHandler = evt => {
setContent(evt.target.value);
};
return (
<wrapper>
<span id="hide">{content}</span>
<input type="text" autoFocus style={{ width }} onChange={changeHandler} />
</wrapper>
);
};
问题是我不知道如何查询跨度的宽度,以便随后更改输入的宽度(使用 setWidth
)。
我怎样才能做到这一点?
嗯,这已经足够有趣了! 我尝试了几个不同的想法,但 none 中的想法完美运行 - 特别是如果它们是用稍微体面的代码编写的。
不过我发现了这个 post 并决定尝试一下。
我敢肯定它有缺陷,例如,除非我使用等宽字体,否则它确实很有趣。但也许有一些 css 技巧可以解决这个问题?
// Normally I'd go for ES6 imports, but to make it run as a Whosebug snippet I had to do it this way
const { useState, useRef } = React;
const GrowingInput = () => {
const [width, setWidth] = useState(0);
const changeHandler = evt => {
setWidth(evt.target.value.length);
};
return (
<input style={{ width: width +'ch'}} type="text" autoFocus onChange={changeHandler} />
)
};
const App = () => {
return (
<p>Lorem ipsum {<GrowingInput />} egestas arcu.</p>
);
};
// Render it
ReactDOM.render(<App />, document.getElementById("react"));
input {
font-family: Courier;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
您是否考虑过使用 contenteditable
?
https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Editable_content
折腾了很久,终于找到解决办法了!
import React, { useState, useRef, useEffect } from 'react';
export default () => {
const [content, setContent] = useState('');
const [width, setWidth] = useState(0);
const span = useRef();
useEffect(() => {
setWidth(span.current.offsetWidth);
}, [content]);
const changeHandler = evt => {
setContent(evt.target.value);
};
return (
<wrapper>
<span id="hide" ref={span}>{content}</span>
<input type="text" style={{ width }} autoFocus onChange={changeHandler} />
</wrapper>
);
};
为了获得对 #hide
跨度的引用,我使用了 useRef
。然后,width
状态变量可以通过 useEffect
中定义的函数更新,每次 content
更改时都会调用该函数。
我还必须将 #hide
的 css 中的 display: none
切换为 position: absolute
和 opacity: 0
,否则 targetRef.current.offsetWidth
会始终为 0。
这里是a working demo。