#javascript #css #reactjs #styled-components #react-hooks
#javascript #css #reactjs #styled-компоненты #реагирующие крючки
Вопрос:
Я пытаюсь создать этот TextArea
компонент, который использует React hook и 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
возвращается ноль.
Мне нужен способ измерить высоту текстового содержимого внутри textarea
. Я видел здесь несколько вопросов о SO, которые рекомендовали сделать это, установив для height
элемента очень маленькое значение, прежде чем запрашивать scrollHeight
.
Действительно, это дает мне отрицательный результат deltas
, который я хочу, но это просто останавливает любое расширение или сжатие, и вместо этого я получаю полосу прокрутки. Убедитесь в этом, переключив строку с комментариями textAreaRef.current.style.height = "2px";
. Некоторые способы зависания компонента height='2px'
. Я не знаю.
Изолированная среда кода с рабочим примером (обратите внимание на журналы консоли)
Есть идеи, что происходит не так?
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 amp;amp; 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;
Ответ №1:
Просто придумал решение:
Чтобы получить содержимое height
внутри textarea
, сначала нам нужно установить его height
свойству значение 0px
, а затем получить его scrollHeight
.
Но когда вы делаете это, вы в конечном итоге создаете встроенный стиль с height=0px
, и он получает наивысший приоритет правил CSS, поэтому вам нужно отменить его с помощью:
textAreaRef.current.removeAttribute('style');
Это необходимо, потому что весь мой CSS применяется styled-components, который использует <style>
html-тег внутри <head>
, который имеет более низкий приоритет, чем встроенный CSS.
Итак, окончательный и рабочий код:
TextArea.js
function TextArea(props) {
const idealHeight = useRef(32);
const lastScrollHeight = useRef(30);
const textAreaRef = useRef(null);
if (textAreaRef.current != null amp;amp; 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'}
/>
);
}