javascript - 如何创建一个高度自适应的textarea
怪我咯
怪我咯 2017-04-10 14:53:56
[JavaScript讨论组]

我注意到现在SF的评论框已经是高度自适应了,也就是说无论你输入多少个字也不会有那个讨厌的滚动条了,这点很好。我大概看了一下它的技术实现,好像是把textarea替换成一个p,然后把当前的p的contentEditable设置为true。这个实现跟quora的实现比较像。

但是这种实现有个问题,就是对浏览器的支持不是太好,当然SF是明确不支持IE6的,其它版本的IE我手头没有,不知道支持情况如何。就通常情况来说,ie对contentEditable需要做特别多hack才能保持兼容。另一个浏览器就是opera,opera对p的contentEditable支持是最近才开始的。

另一种实现就是,你在网上搜索就会得到的答案,用代码来说话就是

$('textarea').keyup(function () {
    $(this).height(this.scrollHeight);
});

基本上所有的jquery插件核心都是这段代码,但是实际上它的效果非常坑爹

  1. 它响应的是keyup事件,因此也就是说肯定会有延迟。其视觉表现就是,先出现一个滚动条,然后这个文本框再被拉长。这样的体验非常别扭。
  2. 它也有兼容性问题,再某些浏览器上(比如safari),它的scrollHeight会莫名奇妙地多出一些,看起来非常奇怪。

以上就是我对这个功能的分析,我想要的就是一个普通的文本框,在大部分浏览器(可以忽略ie6)下都能敏捷地响应拉伸。如果你是用contentEditable实现,你需要支持以下功能

  1. 拷贝文字时只拷贝纯文本,html会被过滤掉
  2. 换行支持良好
  3. 支持undo和redo

这种文本框体验上其实非常好,如果能在这里讨论出一种比较好地解决方案,也可以造福很多前端开发者。

怪我咯
怪我咯

走同样的路,发现不同的人生

全部回复(5)
高洛峰

终极答案

前些日子有过textarea高度自适应的需求,找到一个插件flexText,
虽然没有用上去,但是的精简的代码很吸引我。

它是原理是这样的,HTML结构如下:

<p class="expandingArea ">
    <pre><span></span><br></pre>
    <textarea placeholder="输入文字"></textarea>
</p>

其中的expandingArea的样式仅有

.expandingArea{
    position:relative;
}

目的是用于textarea相对于expandingArea绝对定位:

textarea{
    position:absolute;
    top:0;
    left:0;
    height:100%;
}

通过这样的样式设置,textArea的高度会始终等于expandingArea的高度,要让textarea的高度变化也只需要调整
expadingArea的高度即可。那么怎么样让expandingArea的高度变化随内容高度变化而变化呢?pre是比较重要的
东西。

pre{
    display:block;
    visibility:hidden;
}

pre以块形式存在,并且不可见,但是是占用空间的,不像display:none;什么空间也不占。这时需要把textarea中的内容实实的同时到pre里的span标签中,因为pre没有postion:absolute所以它的高度会一直影响expandingArea的高度。总结原理就是:pre会随内容的高度变化而变化,expandingArea的高度又随pre变化,因为textarea的高度100%textarea的高度会随expandingArea变化,只要同步textarea的内容到pre中,就达到一个textarea随内容高度变化的目的了。

关于这个方法的兼容性问题 在这个方法的创始人博客有提到NEIL JENKINS。个人觉得这个方法是牛逼的,没有通过计算,逻辑上它像上思维推导,代码实现不复杂,轻松愉快。在这个例子中又看到了一次合理的结构可以简化代码的案例:)。

怪我咯

可以添加一个隐藏的textArea(类似1楼的方法),取这个textArea的scrollHeight然后设置给输入的textArea,不过这里还是要处理取值后的一些兼容性问题。关于keyup事件的问题,最好是用oninput事件和onpropertychange事件来替代,这样可以处理用鼠标添加或删除文字的问题,不过貌似ie9下使用backspace键删除文字不会触发onpropertychange事件,需要单独处理一下

巴扎黑

表示回车的时候增加一字行高就应该不会出现滚动条闪烁的问题了吧?

/** fake code **/
textarea.keydown = function(e){
    if e.keycode == 13 { //忘了回车的 key code 是不是13了
        textarea.height = textarea.height + 1em;
    }
}
伊谢尔伦

试一下

/** fake code **/
textarea.keydown = function(e){
    if e.keycode == 13 { //忘了回车的 key code 是不是13了
        textarea.height = textarea.height + 1em;
    }
}
大家讲道理

我的思路是,用一个p实时去获取textarea的内容,因为p高度是根据内容变化而变化的。我们可以得到p的高度,再反过来把p的高度设置给textarea。

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号