还有另一个关于这个的帖子,我试过了。但有一个问题:如果你删除内容,文本区域不会缩小。我找不到任何方法将其缩小到正确的大小- clientHeight值返回为文本区域的完整大小,而不是它的内容。
该页面的代码如下:
function FitToContent(id, maxHeight)
{
var text = id && id.style ? id : document.getElementById(id);
if ( !text )
return;
var adjustedHeight = text.clientHeight;
if ( !maxHeight || maxHeight > adjustedHeight )
{
adjustedHeight = Math.max(text.scrollHeight, adjustedHeight);
if ( maxHeight )
adjustedHeight = Math.min(maxHeight, adjustedHeight);
if ( adjustedHeight > text.clientHeight )
text.style.height = adjustedHeight + "px";
}
}
window.onload = function() {
document.getElementById("ta").onkeyup = function() {
FitToContent( this, 500 )
};
}
这是一个angularjs指令,用于panzi的答案。
module.directive('autoHeight', function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
element = element[0];
var resize = function(){
element.style.height = 'auto';
element.style.height = (element.scrollHeight)+'px';
};
element.addEventListener('change', resize, false);
element.addEventListener('cut', resize, false);
element.addEventListener('paste', resize, false);
element.addEventListener('drop', resize, false);
element.addEventListener('keydown',resize, false);
setTimeout(resize, 100);
}
};
});
HTML:
<textarea ng-model="foo" auto-height></textarea>
改进的响应式纯JS解决方案,以@DreamTeK的第二个选项为基础
下面还处理了底部填充以及窗口大小的调整。像这样,这对我来说是一个近乎完美的解决方案。非常感谢他。
let textareas = document.getElementsByClassName("auto-resize-textarea");
// Loop through textareas and add event listeners as well as other needed css attributes
for (const textarea of textareas) {
// Initially set height as otherwise the textarea is not high enough on load
textarea.style.height = textarea.scrollHeight.toString();
// Hide scrollbar
textarea.style.overflowY = 'hidden';
// Call resize function with "this" context once during initialisation as it's too high otherwise
resizeTextarea.call(textarea);
// Add event listener to resize textarea on input
textarea.addEventListener('input', resizeTextarea, false);
// Also resize textarea on window resize event binding textarea to be "this"
window.addEventListener('resize', resizeTextarea.bind(textarea), false);
}
function resizeTextarea() {
// Textareas have default 2px padding and if not set it returns 0px
let padding = window.getComputedStyle(this).getPropertyValue('padding-bottom');
// getPropertyValue('padding-bottom') returns "px" at the end it needs to be removed to be added to scrollHeight
padding = parseInt(padding.replace('px',''));
this.style.height = "auto";
this.style.height = (this.scrollHeight) + "px";
}
textarea {
width:40%;
padding:20px 25px;
border-radius: 20px;
}
<textarea class="auto-resize-textarea">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</textarea>
<textarea placeholder="Type, paste, cut text here..." class="auto-resize-textarea"></textarea>
注意:jsfiddle有一个奇怪的问题,文本区域太高,底部有太多的空间,但是复制和粘贴这段代码到一个空的html文件是完美的。
有一个小问题,但当滚动条出现在页面和文本区域收缩和包装文本,并创建一个新的行。上面的函数没有考虑到这一点,我提出了一个问题,但似乎没有人知道解决办法。如果你有解决这个问题的建议,我将非常高兴。
React的一个示例实现:
const {
useLayoutEffect,
useState,
useRef
} = React;
const TextArea = () => {
const ref = useRef();
const [value, setValue] = useState('Some initial text that both wraps and uses\nnew\nlines');
// This only tracks the auto-sized height so we can tell if the user has manually resized
const autoHeight = useRef();
useLayoutEffect(() => {
if (!ref.current) {
return;
}
if (
autoHeight.current !== undefined &&
ref.current.style.height !== autoHeight.current
) {
// don't auto size if the user has manually changed the height
return;
}
ref.current.style.height = "auto";
ref.current.style.overflow = "hidden";
const next = `${ref.current.scrollHeight}px`;
ref.current.style.height = next;
autoHeight.current = next;
ref.current.style.overflow = "auto";
}, [value, ref, autoHeight]);
return (
<textarea
ref={ref}
style={{
resize: 'vertical',
minHeight: '1em',
}}
value={value}
onChange={event => setValue(event.target.value)}
/>
);
}
ReactDOM.render(<TextArea />, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="app"></div>
我创建了一个小的(7kb)自定义元素,为您处理所有这些调整大小的逻辑。
它可以在任何地方工作,因为它是作为自定义元素实现的。包括:虚拟dom (React, Elm等),服务器端呈现的东西,如PHP和简单乏味的HTML文件。
除了监听输入事件外,它还有一个计时器,每100毫秒触发一次,以确保在文本内容通过其他方式发生变化的情况下,事情仍在工作。
下面是它的工作原理:
// At the top of one of your Javascript files
import "autoheight-textarea";
或作为脚本标记包含
<script src="//cdn.jsdelivr.net/npm/autoheight-textarea@1.0.1/dist/main.min.js"></script>
然后像这样包装你的textarea元素
HTML文件
<autoheight-textarea>
<textarea rows="4" placeholder="Type something"></textarea>
<autoheight-textarea>
React.js组件
const MyComponent = () => {
return (
<autoheight-textarea>
<textarea rows={4} placeholder="Type something..." />
</autoheight-textarea>
);
}
下面是Codesandbox上的一个基本演示:https://codesandbox.io/s/unruffled-http-2vm4c
你可以在这里获取软件包:https://www.npmjs.com/package/autoheight-textarea
如果你只是想看看调整大小的逻辑,你可以看看这个函数:https://github.com/Ahrengot/autoheight-textarea/blob/master/src/index.ts#L74-L85