前段时间做了一个textarea多行输入框,输入文本自动上顶,到第5行高度固定,且可滑动查看输入内容。(类似微信聊天输入框功能)
开始的思路是取出textarea的value值,然后将这个值放到一个隐藏域(div或者span)中。然后通过比较textarea与隐藏域的width值,来人为的追加"\n",(其实textarea中的折行并没有真正的换行,只有enter键才会触发换行)最后split("\n"),得到一个数组,该数组的长度即为textarea的行数。
试过之后,发现这种方法存在精度上的误差,根本原因是textarea的属性和span不同,比如说字符间距。
项目需求是这样的:
源文件:
(function (root, factory) {
'use strict';
//根据项目的实际情况,不同的引入方式
if (typeof define === 'function' && define.amd) {
define([], factory);
} else if (typeof exports === 'object') {
module.exports = factory();
} else {
root.autosize = factory();
}
}(this, function () {
function main(ta) {
if (!ta || !ta.nodeName || ta.nodeName !== 'TEXTAREA' || ta.hasAttribute('data-autosize-on')) { return; }
var maxHeight;
var heightOffset;
function init() {
var style = window.getComputedStyle(ta, null); // 详细介绍getComputedStyle函数 http://www.zhangxinxu.com/wordpress/2012/05/getcomputedstyle-js-getpropertyvalue-currentstyle/
if (style.resize === 'vertical') {
ta.style.resize = 'none';
} else if (style.resize === 'both') {
ta.style.resize = 'horizontal';
}
ta.style.wordWrap = 'break-word';// horizontal overflow 设置为hidden,所以用 word-wrap:break-word 来控制textarea 的宽度是必要的
// 当 textarea 的 overflow-y:hidden, Chrome/Safari浏览器不会由空格引起页面的回流
// 可以通过去除滚动条来禁止页面回流
var width = ta.style.width;
ta.style.width = '0px';
ta.offsetWidth;//这里会触发页面回流
ta.style.width = width;
maxHeight = style.maxHeight !== 'none' ? parseFloat(style.maxHeight) : false;//未设置最大高度,高度可以一直自适应
if (style.boxSizing === 'content-box') {
heightOffset = -(parseFloat(style.paddingTop)+parseFloat(style.paddingBottom));
} else {
heightOffset = parseFloat(style.borderTopWidth)+parseFloat(style.borderBottomWidth);
}
adjust();
}
function adjust() {
var startHeight = ta.style.height;
var htmlTop = document.documentElement.scrollTop;
var bodyTop = document.body.scrollTop;
var fontSize = parseFloat($('html')[0].style.fontSize) * 1.75 + "px";//行高
ta.style.height = fontSize;
var endHeight = ta.scrollHeight+heightOffset;
if (maxHeight !== false && maxHeight < endHeight) {
endHeight = maxHeight;
if (ta.style.overflowY !== 'scroll') {
ta.style.overflowY = 'scroll';
}
} else if (ta.style.overflowY !== 'hidden') {
ta.style.overflowY = 'hidden';
}
ta.style.height = endHeight +'px';
// 防止滚动条位置跳跃
document.documentElement.scrollTop = htmlTop;
document.body.scrollTop = bodyTop;
if (startHeight !== ta.style.height) {
var evt = document.createEvent('Event');
evt.initEvent('autosize.resized', true, false);
ta.dispatchEvent(evt);
}
}
//兼容IE9
if ('onpropertychange' in ta && 'oninput' in ta) {
ta.addEventListener('keyup', adjust);
}
window.addEventListener('resize', adjust);
ta.addEventListener('input', adjust);
ta.addEventListener('autosize.update', adjust);
ta.addEventListener('autosize.destroy', function(style){
window.removeEventListener('resize', adjust);
ta.removeEventListener('input', adjust);
ta.removeEventListener('keyup', adjust);
ta.removeEventListener('autosize.destroy');
Object.keys(style).forEach(function(key){
ta.style[key] = style[key];
});
ta.removeAttribute('data-autosize-on');
}.bind(ta, {
height: ta.style.height,
overflow: ta.style.overflow,
overflowY: ta.style.overflowY,
wordWrap: ta.style.wordWrap,
resize: ta.style.resize
}));
ta.setAttribute('data-autosize-on', true);
ta.style.overflow = 'hidden';
ta.style.overflowY = 'hidden';
init();
}
// IE8不支持
if (typeof window.getComputedStyle !== 'function') {
return function(elements) {
return elements;
};
} else {
return function(elements) {
if (elements && elements.length) {
Array.prototype.forEach.call(elements, main);
} else if (elements && elements.nodeName) {
main(elements);
}
return elements;
};
}
}));
引入:
var $dom = this.$dom;
var oldElHeight = null;
Array.prototype.forEach.call(document.querySelectorAll('textarea'), function(el){
oldElHeight = el.style.height;
el.addEventListener('autosize.resized',function(){
if ($("#hasSended").html() == "") {//最后一次oldElHeight会一直保存在这里,所以点击发送之后,两边按钮
//样式会发生错乱,这里用来记录点击发送后,初始化oldElHeight的高度,第一次不会监听。
oldElHeight = "";
}
var nowElHeight = this.style.height;
if(!!oldElHeight && !!nowElHeight && oldElHeight != nowElHeight){
//样式设置
var adjust = parseFloat(nowElHeight) - parseFloat(oldElHeight);
$dom.speakBottomK.css("height",parseFloat($dom.speakBottomK.css("height")) + adjust + 'px');
$dom.speakInputCot.css("height",parseFloat($dom.speakInputCot.css("height")) + adjust + 'px');
$dom.toVoiceSwitch.css("margin-top",parseFloat($dom.toVoiceSwitch.css("margin-top")) + adjust + 'px');
$dom.sendQues.css("margin-top",parseFloat($dom.sendQues.css("margin-top")) + adjust + 'px');
}
oldElHeight = nowElHeight;
$("#hasSended").html("已发送");//两个js文件 设置隐藏域来判断是否点击了发送按钮
});
});
factory(document.querySelectorAll('textarea'));