在用一个简单的Web端的 Markdown 编辑器时,我需要一个能让用户输入文本的东西。我首先想到的是使用一个具有可编辑属性的DIV。但是这种方式引入了许多我不想去解决的问题。我仅仅需要一种简单傻瓜式的方案——美好的TEXTAREA。
但是文本域同样也有一个大问题:它们会有一个默认的固定高度。你可以设置 rows 属性来告诉页面该展示多少行,也可以设置文本域的 style.height 属性。但不幸的是,文本域没有自动设置高度(auto-height)的属性。
我的想法
在每次改变文本时,我们必须计算内容的高度是多少。幸运的是,有个办法可以实现。element.scrollHeight
可以忽略可见滚动条,得到内容的高度。为了减小(文本域)尺寸我们每次将高度设置为0,这样scrollHeight就返回所需要的最小高度而不会多余。例如:当用户删除一行的时候。
同样我们需要计算边框(border)和轮廓(outline)的尺寸,这样文本就不会被截断,也不会出现滚动条。
然后我们设置style.height
属性为已经计算好的高度。
为了每次都执行上面的动作,我们使用oninput
事件,这个事件在每次文本内容改变时被触发。这与onchange
事件相反,onchange
只会在用户点击时触发。
看看代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
<textarea data-adaptheight rows="3" cols="40" placeholder="Your input" style="padding: 16px; line-height: 1.5;"></textarea> <script> (function() { function adjustHeight(textareaElement, minHeight) { // compute the height difference which is caused by border and outline // 计算因边框和轮廓产生的高度差异 var outerHeight = parseInt(window.getComputedStyle(el).height, 10); var diff = outerHeight - el.clientHeight; // set the height to 0 in case of it has to be shrinked // 设置高度为0以防需要收缩(高度) el.style.height = 0; // set the correct height // el.scrollHeight is the full height of the content, not just the visible part // 设置正确的高度 // el.scrollHeight 是文本内容的全部高度,而不仅仅是可见部分的。 el.style.height = Math.max(minHeight, el.scrollHeight + diff) + 'px'; } // we use the "data-adaptheight" attribute as a marker // 我们使用"data-adaptheight"属性作为一个标记 var textAreas = document.querySelectorAll('textarea[data-adaptheight]'); // iterate through all the textareas on the page // 迭代本页所有的文本域 for (var i = 0, l = textAreas.length; i < l; i++) { var el = textAreas[i]; // we need box-sizing: border-box, if the textarea has padding // 如果文本域有边距,我们需要设置box-sizing: border-box el.style.boxSizing = el.style.mozBoxSizing = 'border-box'; // we don't need any scrollbars, do we? :) // 我们不需要滚动条,不是么? :) el.style.overflowY = 'hidden'; // the minimum height initiated through the "rows" attribute // 通过"rows"属性初始化的最小高度 var minHeight = el.scrollHeight; el.addEventListener('input', function() { adjustHeight(el, minHeight); }); // we have to readjust when window size changes (e.g. orientation change) // 当窗口大小改变时,我们需要重新调整高度(例如方向变化) window.addEventListener('resize', function() { adjustHeight(el, minHeight); }); // we adjust height to the initial content // 我们调整初始内容的高度 adjustHeight(el, minHeight); } }()); </script> |
示例
输入一些文本体验下。初始高度为3行。
http://jsfiddle.net/5h4fauq8/1/
权衡
每次键盘事件都会造成页面重绘。因为我们会设置文本域的高度为0然后设置为计算的值。然而这是可以忽略的,因为大多数用户在一秒之内最多只能打几个字。因此这不会造成任何明显的性能缺陷。
在何处使用?
在许多场景下这个都是有用的。其中包括:
- 文本编辑器
- 代码编辑器
- 评论框
你喜欢这个么? 你已经在使用了么? 就在下面进行评论吧。:)