尝试创建具有textarea的React组件,该组件会根据内容高度自动扩展和收缩(使用沙盒)

时间:2019-04-03 19:17:07

标签: javascript css reactjs styled-components react-hooks

我正在尝试构建使用React钩子和TextArea的{​​{1}}组件。

当我的styled-components换行时,一切都会顺利进行。扩展功能按预期工作。

基本上,我正在做的是:

  • 使用textarea-textAreaRef存储对useRef()元素的引用
  • 使用textarea-lastScrollHeight存储最后一个useRef()
  • 使用ScrollHeight-idealHeight存储useRef()的理想高度

我根据存储在先前渲染中的textarea的值来计算idealHeight。然后,我将其与lastScrollHeight的当前值进行比较,并计算出textAreaRef.current.scrollHeight

然后,我计算delta并将其作为idealHeight.current = idealHeight.current + delta发送到我的样式组件props以设置TextAreaInput

问题

height在添加新行时增加,并返回正数scrollHeight。但是,delta不会在删除行时减少。因此scrollHeight返回零。

我需要一种方法来测量delta内文本内容的高度。我在SO上看到一些问题,建议通过在请求textarea之前将元素的height设置为一个很小的值来做到这一点。

的确,这给了我想要的负scrollHeight,但是这只是停止了任何扩大或缩小,我得到了滚动条。通过切换注释行deltas可以看到这一点。组件如何卡在textAreaRef.current.style.height = "2px";上的一些信息。我不知道。

Code SandBox with working example(注意控制台日志)

有什么想法吗?

TextArea.js

height='2px'

1 个答案:

答案 0 :(得分:1)

只是想出了一个解决方案:

为了获取height中的内容textarea,首先我们需要将其height属性设置为0px,然后获取其scrollHeight

但是,当您这样做时,最终会使用height=0px创建内联样式,并且该样式获得CSS规则的最高优先级,因此需要使用以下方法取消设置:

textAreaRef.current.removeAttribute('style');

这是必需的,因为我的所有CSS都是由样式组件应用的,该组件使用<style>内的<head> html标记,该标记的优先级低于嵌入式CSS。

最后的工作代码是:

TextArea.js

function TextArea(props) {

  const idealHeight = useRef(32);
  const lastScrollHeight = useRef(30);
  const textAreaRef = useRef(null);

  if (textAreaRef.current != null && textAreaRef.current != undefined) {

    textAreaRef.current.style.height = '0px'; // This creates an inline style

    let scrollHeight = textAreaRef.current.scrollHeight;

    const style = window.getComputedStyle(textAreaRef.current);

    textAreaRef.current.removeAttribute('style'); // The inline style must be removed

    let delta = scrollHeight-lastScrollHeight.current;

    lastScrollHeight.current = scrollHeight;

    idealHeight.current = idealHeight.current + delta;

  }

  return(
    <TextAreaInput
      placeholder={props.placeholder}
      value={props.value}
      onChange={props.onChange}
      ref={textAreaRef}
      idealHeight={idealHeight.current + 'px'}
    />
  );

}