HTML Contenteditable: ограничение операций редактирования и копирование обновленного текста - PullRequest
0 голосов
/ 14 июня 2019

У меня есть элемент contenteditable p.Я хотел бы ограничить возможные операции редактирования вставкой и удалением запятых.Я также хочу скопировать обновленное содержимое в другой div.Кажется, что эти две цели трудно совместить:

  • Кажется, мне нужно прослушать keydown события, чтобы предотвратить изменение текста с помощью event.preventDefault(), если есть какая-либо другая клавиша, кроме backspace илизапятая была нажата.Когда я слушаю keyup, event.preventDefault() выполняется слишком поздно, и содержимое обновляется независимо от того, какая клавиша была нажата.

  • Но мне может потребоваться дождаться обновления keyupсодержание абзацев, чтобы я мог скопировать текст.Если я использую keydown, я получаю исходный текст.

Я использую Vue.В HTML-коде @keydown='evaluate($event)' просто присоединяет слушателя и разрешает доступ к переменной события, используя.

Редактировать: это мой оригинальный код, см. Также фрагмент (без Vue) ниже.

HTML

<p @keydown='evaluate($event)' id='text' contenteditable>
    Some text
</p>

JS

evaluate: function(storeResponse = true, event) {

    // Stop if any key except comma or backspace was pressed. Only works well with keydown.
    if (! [',', 'Backspace'].includes (event.key)) {
        event.preventDefault();
        return;
    }

    // Otherwise, copy the updated content. Only works well with keyup.
    let textContent = document.getElementById('text').textContent;

    // Paste updated content to another p
    document.getElementById('original-text').innerText = textContent;
}

document.getElementById('text').addEventListener('keydown', evaluate);

function evaluate() {
  // Stop if any key except comma or backspace was pressed.
  // Only works well with keydown.
  if (![',', 'Backspace'].includes(event.key)) {
    event.preventDefault();
    return;
  }

  // Otherwise, copy the updated content. Only works well with keyup.
  let textContent = document.getElementById('text').textContent;

  // I need to paste the updated content to another div, but just log it for this snippet
  console.log(textContent);
}
<p @keydown='evaluate' id='text' contenteditable>
  Some text
</p>

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

Ответы [ 2 ]

0 голосов
/ 16 июня 2019

Вот рабочий фрагмент, основанный на ответе Йом С.

new Vue({
  el: '#app',

  data: () => ({
    content: ''
  }),

  methods: {
    /**
     * Checks whether the keypress should be processed.
     */
    checkKey: function() {
        // Users may only navigate or enter/delete commas
        let permittedKeys = [
            ',',
            'Backspace',
            'ArrowLeft',
            'ArrowRight',
            'ArrowDown',
            'ArrowUp'
        ];

        if (! permittedKeys.includes (event.key)) {
          event.preventDefault();
        }
    },

    evaluate(event) {
      // Stop if any key except comma or backspace was pressed. Only works well with keydown.
      if (![',', 'Backspace'].includes(event.key)) {
        event.preventDefault();
        return;
      }

      // Otherwise, copy the updated content.
      const el = event.target;

      // Paste updated content to another p
      this.content = el.textContent;
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <p @keydown='checkKey' @keyup='evaluate' contenteditable>
    Start typing...
  </p>

  <br />
 
  <p v-text="content">
    Updated text goes here.
  </p>
</div>

Когда вы запустите сниппет, вы увидите, что все еще возможно удалить другие символы, кроме запятых. AFAIK, невозможно получить удаленный символ из ключевых событий, поэтому, похоже, единственный шанс - отменить такие удаления. Для этого я удаляю все запятые как из отредактированного текста, так и из предыдущей версии. Если эти строки не идентичны, я копирую предыдущую версию в элемент contenteditable.

0 голосов
/ 14 июня 2019

Вот один из способов сделать это в одном событии:

new Vue({
  el: '#app',

  data: () => ({
    content: ''
  }),

  methods: {
    evaluate(event) {
      // Stop if any key except comma or backspace was pressed. Only works well with keydown.
      if (![',', 'Backspace'].includes(event.key)) {
        event.preventDefault();
        return;
      }

      // Otherwise, copy the updated content.
      const el = event.target;

      // Paste updated content to another p
      this.content = el.textContent;
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <p @keydown='evaluate' contenteditable>
    Start typing...
  </p>

  <br />
 
  <p v-text="content">
    Updated text goes here.
  </p>
</div>

Быстрый совет:

Передача имени метода без каких-либо аргументов и заключающих в него парейнов автоматически передает связанный объект данных Event методу под капот, если выполняется событие клавиатуры, тогда KeyboardEvent объект данных будет передан методу.

Итак, следующие строки фактически эквивалентны:

<p @keydown='evaluate($event)'></p>

<!-- Or -->

<p @keydown='evaluate'></p>
...