如何实现 textarea 的 autoHeight 功能

这个功能还比较常见,用来获取文本的长宽(避免了计算不准的问题),主要用于实现 textarea 自动变长。

如何实现 textarea 的 autoHeight 功能

可以看到在我们使用 textarea 的时候,有时候需要感知内容的高度,然后动态撑开。(elementUI 的 textarea 就提供了 autosize 的功能。)

那我们也想实现这样的功能应该怎么办呢?

获取内容,然后统计字符个数估算。中文算两个,英文算一个。但是还是有问题的,比如说非等宽字体。

聪明的读者已经看到了我们中间的 div 效果,就是我们想要的高度。也是 elementUI 的方案,创建一个拥有相同样式的 div,然后获取他的高度。


构建相同样式的 DOM

看上去这个方案是最妙的。那么如何构建相同的DOM呢?

既然要构建相同的 DOM,那么我们需要知道 DOM 长什么样子。

那么如何获取样式呢?获取class?获取style?

nonono,我们要用 window.getComputedStyle(el),然后就可以快乐的拿到计算后的属性。

之后我们需要知道什么属性会影响字体排列。

CONTEXT_STYLE = [ 'letter-spacing', 'line-height', 'padding-top', 'padding-bottom', 'font-family', 'font-weight', 'font-size', 'text-rendering', 'text-transform', 'width', 'text-indent', 'padding-left', 'padding-right', 'border-width', 'box-sizing']

因为我们需要重新搞一个DOM节点,而且我们不希望这个过程被用户看到,所以我们要隐藏起来。有什么方案呢?

display:none 这个是不行的,因为 none 之后不会绘制了。也就获取不到宽高了。
opacity:0 这个可以
visibility: hidden; 这个也可以
height:0;overflow:hidden 这个也可以,获取scrollHeight
z-index:-999 这也可以的。
position:absolute;top:-9999px;left:-9999px 也是可以的


elementUI 实现

https://github.com/ElemeFE/element/blob/dev/packages/input/src/calcTextareaHeight.js

let hiddenTextarea;

const HIDDEN_STYLE = `

height:0 !important;

visibility:hidden !important;

overflow:hidden !important;

position:absolute !important;

z-index:-1000 !important;

top:0 !important;

right:0 !important

`;

const CONTEXT_STYLE = [

'letter-spacing',

'line-height',

'padding-top',

'padding-bottom',

'font-family',

'font-weight',

'font-size',

'text-rendering',

'text-transform',

'width',

'text-indent',

'padding-left',

'padding-right',

'border-width',

'box-sizing'

];

function calculateNodeStyling(targetElement) {

const style = window.getComputedStyle(targetElement);

const boxSizing = style.getPropertyValue('box-sizing');

const paddingSize = (

parseFloat(style.getPropertyValue('padding-bottom')) +

parseFloat(style.getPropertyValue('padding-top'))

);

const borderSize = (

parseFloat(style.getPropertyValue('border-bottom-width')) +

parseFloat(style.getPropertyValue('border-top-width'))

);

const contextStyle = CONTEXT_STYLE

.map(name => `${name}:${style.getPropertyValue(name)}`)

.join(';');

return { contextStyle, paddingSize, borderSize, boxSizing };

}

export default function calcTextareaHeight(

targetElement,

minRows = 1,

maxRows = null

) {

if (!hiddenTextarea) {

hiddenTextarea = document.createElement('textarea');

document.body.appendChild(hiddenTextarea);

}

let {

paddingSize,

borderSize,

boxSizing,

contextStyle

} = calculateNodeStyling(targetElement);

hiddenTextarea.setAttribute('style', `${contextStyle};${HIDDEN_STYLE}`);

hiddenTextarea.value = targetElement.value || targetElement.placeholder || '';

let height = hiddenTextarea.scrollHeight;

const result = {};

if (boxSizing === 'border-box') {

height = height + borderSize;

} else if (boxSizing === 'content-box') {

height = height - paddingSize;

}

hiddenTextarea.value = '';

let singleRowHeight = hiddenTextarea.scrollHeight - paddingSize;

if (minRows !== null) {

let minHeight = singleRowHeight * minRows;

if (boxSizing === 'border-box') {

minHeight = minHeight + paddingSize + borderSize;

}

height = Math.max(minHeight, height);

result.minHeight = `${ minHeight }px`;

}

if (maxRows !== null) {

let maxHeight = singleRowHeight * maxRows;

if (boxSizing === 'border-box') {

maxHeight = maxHeight + paddingSize + borderSize;

}

height = Math.min(maxHeight, height);

}

result.height = `${ height }px`;

hiddenTextarea.parentNode && hiddenTextarea.parentNode.removeChild(hiddenTextarea);

hiddenTextarea = null;

return result;

};

微信公众号:前端linong


链接: http://www.fly63.com/article/detial/9772

以上是 如何实现 textarea 的 autoHeight 功能 的全部内容, 来源链接: utcz.com/a/81843.html

回到顶部