version:element-plus 1.0.1-beta.0
这里的指向是element-plus 但应该是一样的
let hiddenTextarea
// 隐藏的textarea样式
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',
]
type NodeStyle = {
contextStyle: string
boxSizing: string
paddingSize: number
borderSize: number
}
type TextAreaHeight = {
height: string
minHeight?: string
}
function calculateNodeStyling(targetElement): NodeStyle {
const style = window.getComputedStyle(targetElement)
// 获取box-sizing属性的值
const boxSizing = style.getPropertyValue('box-sizing')
// 上下padding值
const paddingSize = (
parseFloat(style.getPropertyValue('padding-bottom')) +
parseFloat(style.getPropertyValue('padding-top'))
)
// 上下border
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 }
}
// 创建一个textarea,加入到body中,css隐藏,计算它的高度,然后算出来的就是要自适应的高度,在remove掉
export default function calcTextareaHeight(
targetElement,
minRows = 1,
maxRows = null,
): TextAreaHeight {
// 创建textarea,加入到body中
if (!hiddenTextarea) {
hiddenTextarea = document.createElement('textarea')
document.body.appendChild(hiddenTextarea)
}
const {
paddingSize,
borderSize,
boxSizing,
contextStyle,
} = calculateNodeStyling(targetElement)
// 设置隐藏起来的样式
hiddenTextarea.setAttribute('style', `${contextStyle};${HIDDEN_STYLE}`)
hiddenTextarea.value = targetElement.value || targetElement.placeholder || ''
let height = hiddenTextarea.scrollHeight
const result = {} as TextAreaHeight
// 根据box-sizing来计算height
if (boxSizing === 'border-box') {
height = height + borderSize
} else if (boxSizing === 'content-box') {
height = height - paddingSize
}
hiddenTextarea.value = ''
// 每行的高度
const singleRowHeight = hiddenTextarea.scrollHeight - paddingSize
// 传入最小行数
if (minRows !== null) {
let minHeight = singleRowHeight * minRows
if (boxSizing === 'border-box') {
minHeight = minHeight + paddingSize + borderSize
}
// height 取较大的值
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 取较小的值
height = Math.min(maxHeight, height)
}
// 返回值中的最大高度
result.height = `${ height }px`
// 移除隐藏的textarea
hiddenTextarea.parentNode?.removeChild(hiddenTextarea)
hiddenTextarea = null
return result
}