有时候我们需要一个高度能随内容自动增加的输入框,input
显然不行,因为 input
里的文字是不换行的。文本域 textarea
里的文字倒是换行的,可一旦文字内容超过其高度,textarea
就会增加一个烦人的滚动条,这是很影响视觉的,就如同下面:
那么有没有办法制作一个高度能随文字内容自动增加的输入框呢?答案是肯定的,下面介绍两种方式。
方式一
这种方式依然使用 textarea
, 主要思想是我们将 textarea
放入一个容器中,同时在这个容器中放入一个隐藏的 div (visibility: hidden), 监听 textarea
的输入事件并将其中的文字动态的同步到隐藏的div中,这样div 就可以撑开容器,这时设置 textarea
的高度为 100% 并将其定位到容器的左上角,那么 textarea
的高度自然就是其中文字内容的高度了。
visibility
是一个CSS属性,用来在不更改文档的布局的前提下显示或隐藏元素,它有三个可能的取值:
visible
元素正常显示(默认值);hidden
隐藏元素,但是其他元素的布局不改变,相当于此元素变成透明。
若将其子元素设为 visibility: visible,则该子元素依然可见;collapse
用于表格的行、列、列组和行组,隐藏表格的行或列,并且不占用任何空间。
查看样例:https://mxsyx.site/archives/10/#demo-1
你可能已经注意到了,当我们输入文字时,输入框的高度显然要比文字内容高许多,伴随着输入文字的增多。高度差会越来越大,这是因为隐藏 div
与 文本域 textarea
内字体的尺寸与行高是不同的, div
内的字体尺寸与行高要比 textarea
内的大,所以 div
撑开的容器高度自然要高于 textarea
内的文字内容高度。要解决这个问题,统一它们的字体尺寸与行高就可以了。(注:div
的字体尺寸与行高默认继承自父元素)
查看样例:https://mxsyx.site/archives/10/#demo-2
这样一来高度就一致了。这种方式虽然可以较好的实现高度自适应的输入框,但实现起来总感觉很粗糙,下面这种方式就明显简单多了。
方式二
像 div
, p
, blockquote
这样的元素默认是不可编辑的,但我们可以将其 contenteditable
属性设置为 true
, 使其变为可编辑的。
contenteditable
是一个全局属性,用于指示元素是否可被用户编辑,该属性必须采用以下值之一:
true
或者 '空字符串', 表示该元素是可编辑的;false
, 表示该元素是不可编辑的。- 如果未设置此属性,则其默认值将从其父元素继承。
尝试输入一段文字吧:
是不是很简单呢? 我们也可以使用CSS伪类 :empty, :focus, 实现placeholder
那样的效果
尝试输入一段文字吧:
如果你使用 Vue.js, 我们也可以它封装为一个Vue组件:
{{ innerText }}
接下来在父组件中引用这个组件:
父组件为子组件使用 v-model
指令,将子组件的 value
与 父组件的 msg
双向绑定在一起。当输入事件发生后,子组件调用changeText方法,触发一个 input
事件,父组件监听到此事件,将事件传递过来的数据同步到 msg
上,由于数据是双向绑定的,子组件的 value
值也会相应发生变化。更过原理请参考 自定义组件的-v-model
该篇博客内的代码已同步到Github
参考资料:
[1]. MDN文档 https://developer.mozilla.org/zh-CN/docs/Web/HTML/Global_attributes/contenteditable
[2]. MDN文档 https://developer.mozilla.org/zh-CN/docs/Web/CSS/visibility
[3]. MDN文档 https://developer.mozilla.org/zh-CN/docs/Web/CSS/:empty
[4]. MDN文档 https://developer.mozilla.org/zh-CN/docs/Web/CSS/:focus
[5]. Vue.js官方文档 https://cn.vuejs.org/v2/guide/components-custom-events.html#自定义组件的-v-model