вызвать событие при изменении contenteditable

Когда значение div изменяется, как я могу вызвать событие?

<div class="changeable" contenteditable="true"> Click this div to edit it <div>

Поэтому, когда его содержимое меняется, я хочу создать предупреждение и/или сделать что-то еще:

$('.changeable').text().change(function() {
  alert('Handler for .change() called.');
});

person johnmosly    schedule 06.06.2011    source источник
comment
возможный дубликат событий изменения контента   -  person David d C e Freitas    schedule 09.10.2013
comment
Добавлен новый ответ здесь   -  person Dan Philip    schedule 23.04.2017


Ответы (12)


Просто сохраните содержимое в переменной и проверьте, отличается ли оно после события blur(). Если оно отличается, сохраните новое содержимое.

var contents = $('.changeable').html();
$('.changeable').blur(function() {
    if (contents!=$(this).html()){
        alert('Handler for .change() called.');
        contents = $(this).html();
    }
});

пример: http://jsfiddle.net/niklasvh/a4QNB/

person Niklas    schedule 06.06.2011
comment
Большое спасибо @Niklas! - person Roberto Sepúlveda Bravo; 20.11.2015
comment
Это грязный хак, и его не следует использовать. - person alsdkjasdlkja; 04.10.2016
comment
Изменен код @Niklas и добавлен новый ответ здесь - person Dan Philip; 23.04.2017
comment
Не работает на моем Chrome 65 — только когда «размыто» (сфокусировано). - person Nathan B; 16.06.2018

Вы можете просто использовать событие focus/blur с функцией data() jQuery:

// Find all editable content.
$('[contenteditable=true]')
    // When you click on item, record into data("initialText") content of this item.
    .focus(function() {
        $(this).data("initialText", $(this).html());
    });
    // When you leave an item...
    .blur(function() {
        // ...if content is different...
        if ($(this).data("initialText") !== $(this).html()) {
            // ... do something.
            console.log('New data when content change.');
            console.log($(this).html());
        }
    });
});

ОБНОВЛЕНИЕ: с ванильным JS

// Find all editable content.
var contents = document.querySelectorAll("[contenteditable=true]");
[].forEach.call(contents, function (content) {
    // When you click on item, record into `data-initial-text` content of this item.
    content.addEventListener("focus", function () {
        content.setAttribute("data-initial-text", content.innerHTML);
    });
    // When you leave an item...
    content.addEventListener("blur", function () {
        // ...if content is different...
        if (content.getAttribute("data-initial-text") !== content.innerHTML) {
            // ... do something.
            console.log("New data when content change.");
            console.log(content.innerHTML);
        }
    });
});
person Bruno J. S. Lesieur    schedule 20.12.2013
comment
+1 за то, что это единственное решение моего (неопубликованного) вопроса, как вы можете определить, когда начинается редактирование? ... чтобы вы могли отобразить кнопку сохранения и т. д. ... Все связанные вопросы сосредоточены на обнаружении изменений, а не на начале редактирования сессия... - person A2D; 29.09.2015
comment
+1 за демонстрацию того, как работать со всеми редактируемыми элементами, не ссылаясь конкретно на идентификатор. Отлично работает для создания простой редактируемой сетки с html-таблицей. - person artifex_knowledge; 04.05.2018

лучшим решением для этого в настоящее время является событие ввода HTML5

<div contenteditable="true" id="content"></div>

в вашем jquery.

$('#content').on('input', (e) => {
    // your code here
    alert('changed')
});
person Canaan Etai    schedule 08.11.2016
comment
Прекрасно работает! ???? - person Michael; 05.10.2017
comment
Вероятно, это должен быть принятый ответ - я считаю его самым простым, а также лучшим. - person LMD; 26.05.2019
comment
Единственная проблема заключается в том, что input запускается при каждом нажатии клавиши, тогда как change запускается в конце после ввода всех данных. В моей ситуации мне нужно, чтобы событие изменения не вводилось - person Luke T O'Brien; 24.07.2020

Для этого я создал плагин jQuery.

(function ($) {
    $.fn.wysiwygEvt = function () {
        return this.each(function () {
            var $this = $(this);
            var htmlold = $this.html();
            $this.bind('blur keyup paste copy cut mouseup', function () {
                var htmlnew = $this.html();
                if (htmlold !== htmlnew) {
                    $this.trigger('change')
                }
            })
        })
    }
})(jQuery);

Вы можете просто позвонить $('.wysiwyg').wysiwygEvt();

Вы также можете удалить / добавить события, если хотите

person Blowsie    schedule 04.06.2013
comment
Что такое that в that.bind(...)? - person Alexis Wilke; 29.12.2013
comment
blur keyup paste copy cut mouseup — все возможные события изменения - person Blowsie; 30.12.2013
comment
that.bind(...) должно быть $this.bind(...) - person Ian Tearle; 17.01.2014
comment
Это здорово, за исключением того, что htmlold нужно обновлять при изменении. В противном случае, если он вернется к исходному htmlold, событие не сработает. - person dustinfarris; 09.08.2014

Это проще сделать с помощью EventListener (не метод jQuery):

document.getElementById("editor").addEventListener("input", function() {
   alert("input event fired");
}, false);

person VasG    schedule 08.05.2013
comment
Это хорошо для последних браузеров Mozilla и WebKit, но, к сожалению, не поддерживается для contenteditable ни в одной версии IE или Opera. - person Tim Down; 09.05.2013
comment
это также можно использовать с jquery для упрощения привязки к классам, $('.class').on('input', function(){}) - person haz0rd; 21.01.2014

Это мой подход...

$('.changeable').focusout(function() {
  alert('Handler for .change() called.');
});
person Marcel Barraza    schedule 04.05.2012

Еще одна версия в jquery. Посмотреть в jsFiddle здесь.

var $editableContent = $("#mycontent");

//  Implement on text change
$editableContent.on("focus", function(event) {$(this).data("currentText", $(this).text());});

$editableContent.on("blur", function (event) {
        if ($(this).text() != $(this).data("currentText")) {
                $(this).trigger('change');}});


//  Wire onchange event
$editableContent.on("change", function(){alert("Text changed to: " + $(this).text())});
person dcapelo    schedule 18.02.2016

Вот jquery-версия:

function fix_contenteditableOnchange(obj)
{
     div=$(obj);
     var contents = div.html();
     var onchange = div.attr('onchange');
     div.blur(function() {
      if (contents!=$(this).html()){
        eval(onchange);
        fix_contenteditableOnchange(obj);
      }
     });
}

Попробуйте это.

person Sven    schedule 21.04.2012
comment
Почему рекурсивный вызов? Не могли бы вы просто сделать contents = $(this).html()? - person Alexis Wilke; 29.12.2013

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

var contents = $('.changeable').html();
$('.changeable').blur(function() {
   if (contents!=$(this).html()){
 alert('Handler for .change() called.');
      $(".Apple-tab-span").remove();
       contents = $(this).html();
       contentsTx = $(this).text();
       alert(contentsTx);

   }
});

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

.Apple-tab-span
{
  Display:None;
}

и это также решит проблему.. http://jsfiddle.net/a4QNB/312/

Только что изменил ответ @Nikals ...

person nikunjM    schedule 13.10.2015

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

Идея состоит в том, чтобы сохранить исходное значение и сравнить его с текущим значением в событии «размытие». Я сохраняю исходное значение как атрибут редактируемого тега div (вместо создания переменной для исходного значения). Использование атрибута в качестве контейнера для исходного значения более удобно, когда в таблице есть огромное количество редактируемых элементов div (в виде ячеек). Таким образом, легко получить исходное значение, поскольку вам не нужно создавать много переменных.

См. мой полный пример кода:

редактируемый раздел

<td><div contenteditable="true" class="cell" origin="originValue">originValue</div></td>

обнаружение изменений в размытии

var cells = $("#table").find('td>div[contenteditable=true]');

cells.each(function () {    

        $(this).blur(function() {

                    if ($(this).text() != $(this).attr("origin")) {
                        console.log('changed');
                    }
        });    
});
person Bronek    schedule 31.07.2013
comment
Это не очень хороший подход. Ваше исходное значение может иметь недопустимый html, но браузеры всегда будут пытаться исправить его в редактируемом div, поэтому даже если содержимое на самом деле не изменится, ваше тестовое условие не будет выполнено, потому что браузер преобразовал ваш ‹br› в ‹br›‹/br› - person Vishal Seth; 20.09.2014
comment
Вот в будущем я использовал теги данных для этой цели, и они отлично работают! - person Scott Fraley; 21.07.2017

Что вам нужно сделать, так это объединить события blur и DOMSubtreeModified в элементах contenteditable.

var contentEdited = false;

function fn($el) {
  if (contentEdited) {
    var text = $el[0].innerText.trim();
    console.log(text);
    contentEdited = false;
  }
}
$("div.editable").on("blur", function() {
  fn($(this));
}).on("DOMSubtreeModified", function() {
  contentEdited = true;
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="editable" contenteditable="true">Click this div to edit it<div>

person Dan Philip    schedule 23.04.2017
comment
DOMSubtreeModified со временем исчезнет и поэтому, вероятно, следует избегать в большинстве случаев. Это также может значительно снизить производительность DOM. - person Tim Down; 24.04.2017
comment
Это событие устарело — developer.mozilla.org/en-US/ документы/Архив/События/ - person sarkiroka; 20.04.2020

person    schedule
comment
Спасибо друг. ваше решение помогло мне - person fahim152; 28.03.2020
comment
Когда я использую ваш код в ячейке таблицы, где я хочу изменить одно конкретное значение столбца, предупреждение продолжается бесконечно. Я использовал onfocus и onfocusout, происходит то же самое. Все, что я хочу, это зафиксировать новое значение, когда я перехожу к новой ячейке выше или ниже. onchange тоже не работает. - person AbuTaareq; 12.08.2020