Реализовать очень «послушное» многострочное поле ввода текста.

внешний интерфейс JavaScript
Реализовать очень «послушное» многострочное поле ввода текста.

Введение

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

  Но когда вводимый контент превышает указанные строки, появится полоса прокрутки.Если пользователь хочет просмотреть весь контент, он должен перетаскивать полосу прокрутки вперед и назад. И эта полоса прокрутки появляется только тогда, когда пользователь прокручивает, и в некоторых случаях пользователь может не знать, что в этой области есть еще контент.

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

2. Высокая адаптивность

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

   Это требует большого количества базовых знаний, что мы часто говорим о работе с деталями:

1. высота прокрутки

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

  scrollHeight включает отступ элемента, но не границы и поля элемента. Когда в элементе нет содержимого переполнения, значения scrollHeight и clientHeight совпадают.

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

2. Размер коробки

  Блочная модель в CSS в основном общеизвестна. В CSS можно изменить расчет высоты и ширины блочной модели, установив значение свойства box-sizing. Ниже приведен пример высоты:

  • поле содержимого: значение по умолчанию. Если вы установите высоту элемента 100 пикселей, это означает, что высота области содержимого элемента равна 100 пикселей.Если вы установите отступы и границы, то конечная высота элемента будет 100 пикселей + граница-верх + граница -bottom + padding-top + padding-bottom .
  • border-box: Если вы устанавливаете высоту элемента в 100px, это означает, что окончательная высота элемента равна 100px, а высота области содержимого элемента равна 100px - border-top - border-bottom - отступы сверху - отступы снизу.

   Видно, что при установке свойства height в стиле для элемента необходимо определиться с box-sizing , padding и border элемента.

3. получить вычисляемый стиль

Для новичков в интерфейсах, чтобы получить значение свойства в Box-Simpling Стиль элемента, это может быть желательно в первый раз:

  document.getElementById('demo').style.boxSizing

Но в большинстве случаев это свойство получает пустое значение, потому что он может получить встроенные стили. Если значение свойства Boxsing не устанавливается в свойство стиля, это естественно пустое значение.

   В CSS разработчики могут стилизовать элементы разными способами, и у них разные приоритеты, поэтому для определения окончательного стиля элемента необходим API, и для этого родился метод Window.getComputedStyle().

Метод   Window.getComputedStyle() возвращает объект CSSStyleDeclaration в реальном времени и получает соответствующее значение свойства, вызывая его метод getPropertyValue():

  const style = window.getComputedStyle(el)
  style.getPropertyValue('box-sizing')
4. Осознайте

   С добавлением трех вышеупомянутых точек знаний следующим шагом будет реализация кода:

function AutoSize (el) {
  if (!(this instanceof AutoSize)) {
    return new AutoSize(el)
  }
  if (!el) {
    throw new Error('element can not be empty')
  }
  if (typeof el === 'string') {
    el = document.querySelector(el)
  }
  this.el = el
  const attrs = ['box-sizing', 'padding-top', 'padding-bottom', 'border-top', 'border-bottom']

  // 初始化信息
  this.heightOffset = 0
  const style = window.getComputedStyle(el)
  const [boxSizing, paddingTop, paddingBottom, borderTop, borderBottom] = attrs.map(item => style.getPropertyValue(item))
  if (boxSizing === 'content-box') {
    this.heightOffset = -(parseFloat(paddingTop)) - parseFloat(paddingBottom)
  } else {
    this.heightOffset = parseFloat(borderTop)  + parseFloat(borderBottom)
  }
  this.initEvent()
}

AutoSize.prototype = {
  initEvent () {
    this.listener = this.handleAction.bind(this)
    this.el.addEventListener('input', this.listener, false)
  },
  destroy () {
    this.el.removeEventListener('input', this.listener, false)
    this.listener = null
  },
  handleAction (e) {
    const event = e || window.event
    const target = event.target || event.srcElement
    target.style.height = ''
    target.style.height = target.scrollHeight + this.heightOffset + 'px'
  }
}

!

高度自适应多行文本输入框

   Для высокочастотных инициируемых событий, таких как ввод, обычно необходимо использовать функцию дросселирования или функцию защиты от сотрясений для оптимизации, поэтому я оставляю это на усмотрение читателя.

Три, контентредактируемый

  HTML также имеет особый атрибут --contenteditable, этот атрибут может указать, является ли текущий элемент редактируемым (далее такие элементы вместе называются редактируемыми элементами).Значения этого атрибута следующие:

  • true или пустая строка, указывающая, что элемент доступен для редактирования;
  • false означает, что элемент недоступен для редактирования;
  • только открытый текст обрабатывает только текстовое содержимое;
  • Дополнительные значения см.W3C ContentEditable.

   Когда пользователь вводит содержимое в редактируемый элемент, браузер генерирует соответствующий элемент DOM, поэтому редактируемый элемент может выполнять редактирование форматированного текста, например:medium-editor.

   Однако, поскольку в каждом браузере действуют разные правила генерации тегов, с совместимостью возникает большая проблема.

   Теперь вернемся к необходимости реализовать высокоадаптивное многострочное поле ввода текста, учитывая, что пользователи могут вводить или вставлять форматированный текст, здесь вам нужно установить для свойства contenteditable значение только для открытого текста:

  <div contenteditable="plaintext-only" class="demo" id="js-div" data-placeholder="这是占位文字"></div>

   Теперь этот тег div стал очень адаптивным полем ввода текста, разве это не удивительно! Но не слишком волнуйтесь, есть несколько вещей, которые следует учитывать:

1. заполнитель

   Для серьезного поля ввода должен быть эффект заполнителя:

  [contenteditable=true]:empty::before {
    content: attr(data-placeholder);
    color: red;
    display: block;
  }
2. Значение

   Для тегов textarea вы можете получить содержимое, введенное пользователем, через значение атрибута value. А вот для элементов, у которых установлен атрибут contenteditable, требуется специальный анализ:

  • Если вам нужно получить структуру HTML, вам нужно использовать свойство innerHTML;
  • Если вы получаете только текстовый контент, рассмотрите возможность использования innerText и textContent.

  innerText и textContent снова путаются?Основные различия между ними:

  • textContent получит содержимое всех элементов, включая элементы тегов script и style, а innerText — нет;
  • На innerText влияют стили CSS, и он не будет возвращать текст скрытого элемента, в то время как textContent будет;
  • Текстовое содержимое, возвращаемое innerText, форматируется.

   Поскольку приведенный выше атрибут contenteditable указывает значение атрибута только для открытого текста, значения, полученные этими тремя атрибутами, одинаковы.

3. Другие способы запретить ввод форматированного текста

   Помимо указания значения атрибута только для открытого текста,Чжан СиньсюйЯ написал один много лет назадМоделирование DIV Textarea достигает высокой адаптивности, который реализован через свойства CSS, чтобы разрешить только текстовое содержимое:

  -webkit-user-modify: read-write-plaintext-only;

   Теперь CSS-свойство user-modify заменено на contenteditable, но это по-прежнему очень волшебное CSS-свойство.

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

4. Внедрение поля ввода вопроса с заполнением пробела

   Помимо реализации высокоадаптивных многострочных текстовых полей ввода, редактируемые элементы сильно отличаются от тегов input и textarea, которые могут быть идеально интегрированы в текст, например эффект такого поля ввода с заполнением пустого места:

填空题输入框

4. Резюме

Вышеуказанные являются двумя реализациями высокоадаптивных многострочных текстовых входных ящиков:

  • scrollHeight + getComputedStyle + ввод (событие)
  • contenteditable + куча трюков

  По сравнению со вторым, первый более применим, и это также метод, принятый большинством библиотек компонентов.