Как автоматически изменить размер текстовой области в соответствии с содержимым? - PullRequest
4 голосов
/ 24 сентября 2019

Я пытаюсь автоматически изменить размер textarea, чтобы он соответствовал содержанию в нем, но после нажатия кнопки ввода я сталкиваюсь с заиканием, чтобы перейти к следующей строке.Как я могу это исправить?

Это то, что я пытаюсь сделать, см. Изображение ниже.enter image description here

См. Эту ссылку для примера StackBlitz

КОД

this.form.valueChanges.subscribe(() => {
   const textarea = this.myDiv.nativeElement;
   textarea.addEventListener('keydown', function() {
       setTimeout(() => {
           this.style.cssText = 'height:auto; padding:0';
           this.style.cssText = 'height:' + this.scrollHeight + 'px';
       }, 0);
   });
});

Ответы [ 2 ]

2 голосов
/ 24 сентября 2019

addEventListener здесь избыточно, поскольку valueChanges уже уведомляет вас об изменении поля.Вместо этого обновите высоту, используя ViewChild ссылку myDiv.

this.myForm.valueChanges.subscribe(value => {
    this.myDiv.nativeElement.style.height = 'auto';
    this.myDiv.nativeElement.style.height = `${this.myDiv.nativeElement.scrollHeight}px`;
});

Затем добавьте overflow: hidden к вашему CSS, чтобы полоса прокрутки не отображалась.

textarea {
    resize: horizontal;
    overflow: hidden;
}

Выможно сохранить resize: horizontal;, но он больше не требуется, так как в любом случае он автоматически изменит размер.

Вот рабочий пример для StackBlitz .

1 голос
/ 24 сентября 2019

То, что вы пытаетесь достичь, это очень старый трюк.Я использовал его сам, но пробовал другой подход.

Имеет больше смысла, почему текстовая область искажается, потому что при каждом нажатии клавиши height = 0 вычислялась высота прокрутки, чтобы можно было назначить новую высоту.

Я вычислил fontSize или lineHeight и рассчитал количество линий и начальную высоту, чтобы настроить на основе этого.Таким образом, при каждом нажатии клавиши вы просто назначаете высоту без задания высоты текстовой области = 0

textareaProps = null;
getHeight(element) {
  const lines = element.value.split(/\r\n|\r|\n/).length;
  if(!this.textareaProps) {
    const autoStyle = getComputedStyle(element);
    const lineHeight = parseInt(autoStyle.lineHeight);
    const adjust = parseInt(autoStyle.height) - lineHeight;
    this.textareaProps = {adjust, lineHeight}
  }
  const { adjust, lineHeight } = this.textareaProps;
  const height = lines * lineHeight + adjust;
  return height + 'px';
}

Теперь вам нужно вызвать этот метод, чтобы получить высоту и передать элемент textarea как аргумент.

element.style.cssText = 'height:' + getHeight(element) ;

Редактировать 2

К сожалению, вышеприведенное решение будет работать только при наличии разрывов строки пользователем.Когда вы вводите огромную строку, текстовая область оборачивает ее, но она не увеличивает высоту.Итак, представляем прокси html-элемент, который будет иметь текст, равный значению текстовой области, и предоставит высоту, которую мы можем назначить нашей текстовой области.

textareaProps = null;
getHeight(element) {
  if(!this.textareaProps) {
    const proxy = document.createElement('div');
    const {padding, width, fontSize, height, lineHeight} = getComputedStyle(element);
    const css = [
      'position:absolute',
      'visibility: hidden',
      'pointer-events:none',
      `width: ${width}`,
      `padding:${padding}`,
      `min-height: ${height}`,
      `font-size:${fontSize}`,
      `line-height:${lineHeight}`,
    ].join(';');
    proxy.style.cssText=css;
    this.textareaProps = {
      proxy: document.body.appendChild(proxy), 
      adjust: (parseInt(fontSize))
    };
  }
  const { proxy, adjust} = this.textareaProps;
  proxy.innerText = element.value + '.';
  return (proxy.offsetHeight + adjust) + 'px';
}

Обновлен StackBlitz https://stackblitz.com/edit/next-line-view-child-ssnp4q

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...