高度自适应的 textarea react 解决方案

高度自适应的 textarea

背景介绍

正如我们所知道的 textarea 是一个行内块元素 display: inline-block 并且它的默认宽高由 cols & rows 决定, 也就是说 textarea 的 height 并不会自适应于内容长度.

textarea 的宽高是如何决定的?

参考文章: http://www.zhangxinxu.com/wordpress/2016/02/html-textarea-rows-height/

那么, 我们今天的任务就是来思考如何创建一个 高度内容自适应的 textarea 组件.

我将介绍三种思路实现 高度内容自适应的 textarea.

这三种思路的 React 组件实现代码如下:

https://github.com/teeeemoji/textareaAutoSizeSolutions

所有参考链接(锚点失效, 参考链接在最后)

方案概要

这是三种方案的概述和实现思路的简介, 实现方案 & 遇到的坑 & 拓展知识点, 点击 (查看更多) or 直接看 teeeemoji 的 demo.

  • 方案一: 两次调整 textarea.style.height

    textarea 的 onchange 触发 resize 方法
    下面是 resize 方法的逻辑
    ① textarea.style.height = 'auto';// 让 textarea 的高度恢复默认
    ② textarea.style.height = textarea.scrollHeight + 'px';// textarea.scrollHeight 表示 textarea 内容的实际高度

  • 方案二: 利用一个 ghostTextarea 获得输入框内容高度, 再将这个高度设置给真实的 textarea

    textarea 构建时创建 ghostTextarea, onchange 触发 resize 方法
    ① 创建 textarea 的时候, 同时创建一个一模一样的隐藏 ghostTextarea;
    ② ghostTextarea 的属性全部克隆自 textarea, 但是 ghostTextarea 是隐藏的, 并且 ghostTextarea.style.height = 0; 也就是说 ghostTextarea.scrollHeight 就是 textarea 中内容的真是高度
    resize 方法处理流程

    • step-1: textarea.value 先设置给 ghostTextarea,
    • step-2: 拿到 ghostTextarea.scrollHeight
    • step-2: 将 textarea.style.height = ghostTextarea.scrollHeight
  • 方案三: 使用 (div | p | ...).contenteditable 代替 textarea 作为输入框

    div 是块级元素, 高度本身就是内容自适应的(除非设置 max-width or min-widht
    使用contenteditable 让 div 代替 textarea, 省去各种计算高度的逻辑

方案对比

满分3分, 三种方案通过优化, 在用户体验和兼容性上都能达到满分. 因此差别仅仅在于这几个方案的实现难度. (仅仅是基于 react 组件的实现复杂度).

用户体验对比(在最后面, 简书对 markdown 内嵌 html 支持不友好, 锚点都不能用了)

方案 用户体验 兼容性 易用性 综合评价
方案一 3 3 3 10
方案二 3 3 1 7
方案三 3 3 2 8

毫无疑问方案一是最优选择, 多加1分以示奖励;

方案一: 两次调整 textarea.style.height

实现思路

  1. 渲染一个 textarea 元素