element-ui calcTextareaHeight.js文件源码学习

2018年11月13日Web前端0

input组件之前还有个calcTextareaHeight.js文件没有去看下,现在我们去学习下。

一、calcTextareaHeight.js

该文件是通过获取要计算的textarea上的style,并赋值给js生成的textarea元素,并计算他的高度进而推算可放大和缩小的范围。 首先定义了HIDDEN_STYLE变量,给了一堆能隐藏元素的属性。

而CONTEXT_STYLE中定义了一些需要获取的属性,这些属性会影响到内容的高度。

接下来是calculateNodeStyling函数。首先用w3c标准的getComputedStyle方法获取目标元素的所有计算样式。boxSizing则保存了targetElement的box-sizing样式。paddingSize则保存了targetElement的上下padding和,borderSize保存targetElement的上下border和。contextStyle则是对CONTEXT_STYLE对象中key值遍历获取值,最后以;分隔,组成字符串。

本文件导出了calcTextareaHeight这个方法。

首先,用单例模式只创建一个textarea,用于后面赋值属性计算他的高度。

if (!hiddenTextarea) {
    // 创建textarea节点并插入dom树中
    hiddenTextarea = document.createElement('textarea');
    document.body.appendChild(hiddenTextarea);
}

将刚才获得的目标元素的属性,依次赋值给新建的textarea元素。他的value则是目标元素的内容或placeholder,这儿赋值value是因为这值会影响scrollHeight。

hiddenTextarea.setAttribute('style', `${contextStyle};${HIDDEN_STYLE}`);
hiddenTextarea.value = targetElement.value || targetElement.placeholder || '';

接下来,根据当前的box-sizing值,分情况处理了,

let height = hiddenTextarea.scrollHeight;
const result = {};
// 根据boxSizing做调整,拿到实际赋值的height值
if (boxSizing === 'border-box') {
    // 如果是border-box,原先height值是,height高度减上下border的大小
    height = height + borderSize;
} else if (boxSizing === 'content-box') {
    height = height - paddingSize;
}

这儿加减看得很迷惑,先看下例子,以textarea为例,

#box {
    width: 100px;
    height: 100px;
    padding: 10px;
    border: 10px solid #ccc;
    box-sizing: border-box;
}
<textarea id="box"></textarea>

效果如下,而此处的height实际是content的高度加上下padding值,所以当是border-box时,所以加了borderSize。

下面看下content-box时的情况,需要减去上下padding,这样两种情况下height值就可以一致了。

当没有出现滚动条时,scrollHeight的值就是height,而出现滚动条时,加减也是可以通过height去理解的。

无论是哪种box-sizing,scrollHeight都包含了上下padding值,所以在计算singleRowHeight时,将scrollHeight减去了paddingSize,此时得到的都是实际内容的高度。

当有设置autoSize中的minRows时,以singleRowHeight为基数,minRows为倍数,并且当时border-sizing时,需要加上上下padding和border,因为前面也讲了,singleRowHeight已经时实际的存内容的高度了。并为之设置minHeight。

if (minRows !== null) {
    let minHeight = singleRowHeight * minRows;
    if (boxSizing === 'border-box') {
        minHeight = minHeight + paddingSize + borderSize;
    }
    height = Math.max(minHeight, height);
    result.minHeight = `${ minHeight }px`;
}

而当设置maxRows时,原理也是相同的,不再述说。 最后移除hideenTextarea元素。

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

如果一个节点没有parentNode节点,那么他就不是在dom树上的,而是在内存中,随时可以被回收。讲hiddenTextarea的指向改为null后,原先节点所占用的资源就被回收了。

带注释的源码文件下载:calcTextareaHeight.js