尝试使用textarea创建React组件,该组件根据内容高度自动扩展和缩小(使用Sandbox)

问题描述 投票:1回答:1

我正在尝试构建使用React hook和TextAreastyled-components组件。

当我的textarea获得新线时,一切顺利。扩展功能正在按预期工作。

基本上,我正在做的是:

  • 使用textAreaRef-useRef()将ref存储到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回归零。

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

事实上,这给了我想要的负面deltas,但这只是阻止任何扩展或缩小,而我得到一个滚动条。通过切换注释行textAreaRef.current.style.height = "2px";来查看。一些组件如何卡在height='2px'上。我不知道。

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

有什么想法会出错吗?

TextArea.js

import React, { useRef } from "react";
import styled from "styled-components";

const TextAreaInput = styled.textarea`
  height: ${props => props.idealHeight || "152px"};
  min-height: 32px;
  max-height: 320px;
  line-height: 21px;
  width: 100%;
  resize: vertical;
  box-sizing: border-box;

  border: 1px solid rgb(217, 217, 217);
  padding: 4px 11px;
  text-size-adjust: 100%;
`;

function TextArea(props) {
  const idealHeight = useRef(32);
  const lastScrollHeight = useRef(30);
  const textAreaRef = useRef(null);

  console.log("ANOTHER RENDER...");

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

    // THIS NEXT LINE MAKES THE DELTA CALCULATION CORRECT ON 'SHRINKING'
    // BUT STOPS THE RESIZING

    // textAreaRef.current.style.height = "2px";

    const delta = scrollHeight - lastScrollHeight.current;
    console.log("Delta is: " + delta);

    console.log("Last ScrollHeight: " + lastScrollHeight.current);
    lastScrollHeight.current = scrollHeight;

    console.log("Current ScrollHeight: " + lastScrollHeight.current);

    idealHeight.current = idealHeight.current + delta;

    console.log("IdealHeight :" + idealHeight.current);
  }

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

export default TextArea;
javascript css reactjs styled-components react-hooks
1个回答
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'}
    />
  );

}
© www.soinside.com 2019 - 2024. All rights reserved.