尝试使用基于内容高度自动扩展和收缩的文本区域创建 React 组件(使用 Sandbox)
Trying to create React component with textarea that auto expands and shrinks based on content height (with Sandbox)
我正在尝试构建这个使用 React 钩子和 styled-components
的 TextArea
组件。
当我的 textarea
获得新的线路时一切顺利。扩展功能按预期工作。
我所做的基本上是:
- 使用
textAreaRef
- useRef()
存储对 textarea
元素的引用
- 使用
lastScrollHeight
-useRef()
存储最后一个ScrollHeight
- 使用
idealHeight
-useRef()
存储textarea
的理想身高
我根据存储在先前渲染中的 lastScrollHeight
的值计算 idealHeight
。然后我与 textAreaRef.current.scrollHeight
的当前值进行比较并计算 delta
.
然后我计算 idealHeight.current = idealHeight.current + delta
并将其作为 props
发送到我的样式组件 TextAreaInput
以设置 height
.
问题
添加新行时 scrollHeight
增加,returns 为正数 delta
。但是 scrollHeight
不会在删除行时减少。所以 delta
返回零。
我需要一种方法来测量 textarea
中文本内容的高度。我在 SO 上看到了一些问题,建议通过在请求 scrollHeight
.
之前将元素的 height
设置为非常小的值来执行此操作
确实,这给了我想要的负数 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;
刚想出解决办法:
为了得到textarea
里面的内容height
,首先我们需要将它的height
属性设置为0px
然后得到它scrollHeight
.
但是当你这样做时,你最终会创建一个带有 height=0px
的内联样式,并且它获得 CSS 规则的最高优先级,所以你需要取消它:
textAreaRef.current.removeAttribute('style');
这是必需的,因为我的所有 CSS 都被样式组件应用,它使用 <head>
内的 <style>
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'}
/>
);
}
我正在尝试构建这个使用 React 钩子和 styled-components
的 TextArea
组件。
当我的 textarea
获得新的线路时一切顺利。扩展功能按预期工作。
我所做的基本上是:
- 使用
textAreaRef
-useRef()
存储对textarea
元素的引用 - 使用
lastScrollHeight
-useRef()
存储最后一个ScrollHeight
- 使用
idealHeight
-useRef()
存储textarea
的理想身高
我根据存储在先前渲染中的 lastScrollHeight
的值计算 idealHeight
。然后我与 textAreaRef.current.scrollHeight
的当前值进行比较并计算 delta
.
然后我计算 idealHeight.current = idealHeight.current + delta
并将其作为 props
发送到我的样式组件 TextAreaInput
以设置 height
.
问题
添加新行时scrollHeight
增加,returns 为正数 delta
。但是 scrollHeight
不会在删除行时减少。所以 delta
返回零。
我需要一种方法来测量 textarea
中文本内容的高度。我在 SO 上看到了一些问题,建议通过在请求 scrollHeight
.
height
设置为非常小的值来执行此操作
确实,这给了我想要的负数 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;
刚想出解决办法:
为了得到textarea
里面的内容height
,首先我们需要将它的height
属性设置为0px
然后得到它scrollHeight
.
但是当你这样做时,你最终会创建一个带有 height=0px
的内联样式,并且它获得 CSS 规则的最高优先级,所以你需要取消它:
textAreaRef.current.removeAttribute('style');
这是必需的,因为我的所有 CSS 都被样式组件应用,它使用 <head>
内的 <style>
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'}
/>
);
}