前言
我们平时在使用组件库的时候,input 相关的组件一般会有 autosize 这样的属性,设置以后使得文本域的高度能够根据文本内容自动进行调整,下面我们来看下是怎么实现的。
<el-input
type="textarea"
autosize
placeholder="请输入内容"
v-model="textarea1">
</el-input>
原理
实现文本域的高度能够根据文本内容自动进行调整的思路很简单:监听输入相关的事件,获取到元素的内容高度,修改 textarea 的固定高度。
1. scrollHeight
scrollHeight 是元素的一个只读属性,表示是一个元素内容高度的度量,包括由于溢出导致的视图中不可见内容。
scrollHeight 的值等于该元素在不使用滚动条的情况下为了适应视口中所有内容所需的最小高度。 没有垂直滚动条的情况下,scrollHeight值与元素视图填充所有内容所需要的最小值clientHeight相同。包括元素的padding,但不包括元素的border和margin。scrollHeight也包括 ::before 和 ::after这样的伪元素。
但是直接将 scrollHeight 设置为 textarea 的高度,是不是就可以了?这样是不行的,因为元素的 box-sizing 属性会影响到元素内容区高度的计算方式。
2. box-sizing
content-box告诉浏览器:如果你设置一个元素的宽为100px,那么这个元素的内容区会有100px宽,并且任何边框和内边距的宽度都会被增加到最后绘制出来的元素宽度中。所以元素宽度为width + border + padding。border-box告诉浏览器:如果你将一个元素的width设为100px,那么这100px会包含它的border和padding,内容区的实际宽度是width减去(border + padding)的值。大多数情况下,这使得我们更容易地设定一个元素的宽高。
注: border-box不包含margin
对于 box-sizing 的获取,有一种方式是:
document.getElementById('demo').style.boxSizing
但是这种方式获取到的 box-sizing 大多数情况是空的,因为只能够获取行内样式,若元素的行内样式中没有使用 box-sizing 就获取不到。
不过还有一种更合适的方式,就是下面的 getComputedStyle。
3. getComputedStyle
window.getComputedStyle(el) 可以获取元素最终的样式,然后使用 getPropertyValue() 方法获取相应的属性值。
const style = window.getComputedStyle(el)
style.getPropertyValue('box-sizing')
简单实现
这只是计算高度,我们还需要监听input事件,然后动态修改textarea的高度,这些代码比较简单,这里就不再赘述。
function calcTextareaHeight (el) {
if (typeof el === 'string') {
el = document.querySelector(el)
}
const attrs = ['box-sizing', 'padding-top', 'padding-bottom', 'border-top', 'border-bottom']
let heightOffset = 0
const style = window.getComputedStyle(el)
const [boxSizing, paddingTop, paddingBottom, borderTop, borderBottom] = attrs.map(item => style.getPropertyValue(item))
if (boxSizing === 'content-box') {
heightOffset = -(parseFloat(paddingTop)) - parseFloat(paddingBottom)
} else {
heightOffset = parseFloat(borderTop) + parseFloat(borderBottom)
}
let height = el.scrollHeight + heightOffset
return height;
}