Статьи

Создайте встроенный текстовый редактор с атрибутом contentEditable

Создание встроенного редактора требует усилий. Вы начинаете с переключения редактируемого элемента с помощью поля input или textarea поля. Для беспроблемного взаимодействия с пользователем вам, возможно, придется использовать немного CSS, чтобы согласовать стили замененных элементов с оригинальными. Как только пользователь завершит редактирование, вам снова придется переключать элементы после копирования всего содержимого в исходное.

Атрибут contentEditable облегчает эту задачу. Все, что вам нужно сделать, это установить для этого атрибута значение true и стандартные элементы HTML5 станут редактируемыми. В этом уроке мы создадим встроенный текстовый редактор на основе этой функции.

Этот атрибут может принимать три допустимых значения. Это true , false и inherit . Значение true указывает, что элемент является редактируемым. Пустая строка также будет иметь значение true. false указывает на то, что элемент недоступен для редактирования. Значение inherit является значением по умолчанию. inherit означает, что элемент будет редактируемым, если его непосредственный родитель является редактируемым. Это означает, что если вы сделаете элемент редактируемым, все его дочерние элементы, а не только непосредственные, также станут редактируемыми, если вы явно не установите для их атрибута contentEditable значение false .

Вы можете изменить эти значения динамически с помощью JavaScript. Если новое значение не является ни одним из трех допустимых, оно генерирует исключение SyntaxError .

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

При переключении атрибута contentEditable необходимо знать, какое значение имеет атрибут в настоящее время. Для этого вы можете использовать свойство isContentEditable . Если isContentEditable возвращает true для элемента, тогда элемент в настоящее время редактируемый, в противном случае это не так. Мы будем использовать это свойство в ближайшее время для определения состояния различных элементов в нашем документе.

Первым шагом в создании редактора является создание кнопки для переключения редактирования и некоторых редактируемых элементов.

1
2
3
4
5
6
7
<button id=»editBtn» type=»button»>Edit Document</button>
 
<div id=»editor»>
    <h1 id=»title»>A Nice Heading.</h1>
    <p>Last Edited By — <span id=»author»>Monty Shokeen
    <p id=»content»>Some content that needs correction.</p>
</div>

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

Следующий код JavaScript обрабатывает все редактирование и сохранение.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var editBtn = document.getElementById(‘editBtn’);
var editables = document.querySelectorAll(‘#title, #author, #content’)
 
editBtn.addEventListener(‘click’, function(e) {
  if (!editables[0].isContentEditable) {
    editables[0].contentEditable = ‘true’;
    editables[1].contentEditable = ‘true’;
    editables[2].contentEditable = ‘true’;
    editBtn.innerHTML = ‘Save Changes’;
    editBtn.style.backgroundColor = ‘#6F9’;
  } else {
    // Disable Editing
    editables[0].contentEditable = ‘false’;
    editables[1].contentEditable = ‘false’;
    editables[2].contentEditable = ‘false’;
    // Change Button Text and Color
    editBtn.innerHTML = ‘Enable Editing’;
    editBtn.style.backgroundColor = ‘#F96’;
    // Save the data in localStorage
    for (var i = 0; i < editables.length; i++) {
      localStorage.setItem(editables[i].getAttribute(‘id’), editables[i].innerHTML);
    }
  }
});

Мы используем querySelectorAll() для хранения всех редактируемых элементов в переменной. Этот метод возвращает NodeList который содержит все элементы в нашем документе, которые соответствуют указанным селекторам. Таким образом, легче отслеживать редактируемые элементы с одной переменной. Например, к заголовку нашего документа можно получить доступ с помощью editables[0] , что мы и будем делать дальше.

Затем мы добавляем прослушиватель событий в событие нажатия нашей кнопки. Каждый раз, когда пользователь нажимает кнопку «Редактировать документ», мы проверяем, можно ли редактировать заголовок. Если он не редактируется, мы устанавливаем свойство contentEditable для каждого из редактируемых элементов в значение true . Кроме того, текст 'Edit Document' меняется на 'Save Changes' . После того, как пользователи внесли некоторые изменения, они могут нажать кнопку 'Save Changes' , и сделанные изменения могут быть сохранены навсегда.

Если заголовок редактируемый, мы устанавливаем для свойства contentEditable каждого из редактируемых элементов значение false. На этом этапе мы также можем сохранить содержимое нашего документа на сервере для последующего извлечения или синхронизировать изменения с копией, которая существует где-то еще. В этом уроке я собираюсь сохранить все в localStorage . При сохранении значения в localStorage я использую Id каждого элемента, чтобы убедиться, что я ничего не перезаписываю.

Смотрите мою живую демонстрацию CodePen .

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
if (typeof(Storage) !== «undefined») {
 
  if (localStorage.getItem(‘title’) !== null) {
    editables[0].innerHTML = localStorage.getItem(‘title’);
  }
   
  if (localStorage.getItem(‘author’) !== null) {
    editables[1].innerHTML = localStorage.getItem(‘author’);
  }
   
  if (localStorage.getItem(‘content’) !== null) {
    editables[2].innerHTML = localStorage.getItem(‘content’);
  }
}

Приведенный выше код проверяет, существует ли название, автор или содержимое в localStorage . Если они это сделают, мы устанавливаем innerHTML соответствующих элементов для извлеченных значений.

Смотрите другую демонстрацию CodePen .

Для дальнейшего улучшения нашего встроенного редактора нам нужно внести два изменения. Первый заключается в четком разграничении того, что редактируется, а что нет. Это может быть достигнуто путем изменения внешнего вида редактируемых элементов с помощью CSS. Изменение шрифта и цвета соответствующих элементов должно помочь. Селектор [contenteditable="true"] будет применять следующий стиль к элементам всякий раз, когда атрибут contenteditable имеет значение true .

1
2
3
4
[contenteditable=»true»] {
  font-family: «Rajdhani»;
  color: #C00;
}

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

1
2
3
4
5
setInterval(function() {
  for (var i = 0; i < editables.length; i++) {
    localStorage.setItem(editables[i].getAttribute(‘id’), editables[i].innerHTML);
  }
}, 5000);

Вы также можете сохранить изменения для каждого события keydown .

1
2
3
4
5
document.addEventListener(‘keydown’, function(e) {
  for (var i = 0; i < editables.length; i++) {
    localStorage.setItem(editables[i].getAttribute(‘id’), editables[i].innerHTML);
  }
});

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

Посмотреть демонстрацию CodePen .

contentEditable полезен, когда вам нужно отредактировать несколько элементов на веб-странице. Когда необходимо изменить содержимое всех или почти всех элементов веб-страницы, вы можете использовать свойство designMode . Это свойство применимо ко всему документу. Чтобы включить и off , вы используете document.designMode = 'on'; и document.designMode = 'off'; соответственно.

Это окажется полезным в ситуациях, когда вы дизайнер, а кто-то другой — создатель контента. Вы предоставляете им дизайн и некоторый фиктивный текст. Позже они могут заменить его реальным контентом. Чтобы увидеть designMode в действии, откройте вкладку консоли в инструментах разработчика вашего браузера. Тип document.designMode = 'on'; в консоль и нажмите Enter . Все на этой странице должно быть доступно для редактирования.

Атрибут contentEditable удобен в ситуациях, таких как быстрое редактирование статей или предоставление пользователям возможности редактировать свои комментарии одним щелчком мыши. Эта функция была впервые реализована в IE 5.5. Позже, это было стандартизировано WHATWG. Поддержка браузера тоже довольно хорошая. Все основные браузеры, кроме Opera Mini, поддерживают этот атрибут.

JavaScript стал одним из де-факто языков работы в сети. Это не без кривых обучения, и есть множество фреймворков и библиотек, которые также могут вас занять. Если вы ищете дополнительные ресурсы для обучения или использования в своей работе, посмотрите, что у нас есть на рынке Envato .

В этом руководстве рассматриваются основы атрибута contentEditable и его использование для создания основного встроенного текстового редактора. В следующем уроке вы узнаете, как реализовать панель инструментов и предоставить расширенные возможности редактирования текста.