события изменения contenteditable
Я хочу, чтобы запустить функцию, когда пользователь редактирует содержимое div
с
17 ответов:
Я бы предложил прикреплять слушателей к ключевым событиям, вызванным редактируемым элементом, хотя вам нужно знать, что
keydown
иkeypress
события запускаются до изменения самого содержимого. Это не будет охватывать все возможные способы изменения содержимого: пользователь также может использовать вырезать, копировать и вставлять из меню редактирования или контекстного браузера, поэтому вы можете обрабатыватьcut
copy
иpaste
слишком событий. Кроме того, пользователь может удалить текст или другое содержимое, поэтому там больше событий (mouseup
, например). Вы можете опросить содержимое элемента в качестве запасного варианта.обновление 29 октября 2014
The HTML5
input
событие ответ в долгосрочной перспективе. На момент написания статьи он поддерживается дляcontenteditable
элементы в текущих браузерах Mozilla (от Firefox 14) и WebKit/Blink, но не IE.демо:
document.getElementById("editor").addEventListener("input", function() { console.log("input event fired"); }, false);
<div contenteditable="true" id="editor">Please type something in here</div>
вот более эффективная версия, которая использует
on
для всех contenteditables. Он основан на верхних ответах здесь.$('body').on('focus', '[contenteditable]', function() { const $this = $(this); $this.data('before', $this.html()); }).on('blur keyup paste input', '[contenteditable]', function() { const $this = $(this); if ($this.data('before') !== $this.html()) { $this.data('before', $this.html()); $this.trigger('change'); } });
проект здесь:https://github.com/balupton/html5edit
рассмотрите возможность использования MutationObserver. Эти наблюдатели предназначены для реагирования на изменения в DOM и в качестве производительной замены на Событий Мутации.
плюсы:
- пожары любой происходит изменение, которое трудно достичь, слушая ключевые события, как это предлагается другими ответами. Например, все это хорошо работает: перетаскивание, выделение курсивом, копирование / вырезание / вставка через контекст меню.
- разработанный с учетом производительности.
- простой, понятный код. Гораздо проще понять и отладить код, который слушает одно событие, а не код, который слушает 10 событий.
- Google имеет отличный библиотека резюме мутаций что делает использование MutationObservers очень легким.
плюсы:
- требуется самая последняя версия Firefox (14.0+), Chrome (18+) или IE (11+).
- новый API, чтобы понять
- еще не так много информации о передовой практике или тематических исследованиях
подробнее:
- Я написал немного фрагмент для сравнения использования MutationObserers для обработки различных событий. Я использовал код balupton с его ответ имеет больше всего голосов.
- Mozilla имеет отличную страницу на API
- взгляните на элемент MutationSummary библиотека
non jQuery быстрая и грязный ответ:
function setChangeListener (div, listener) { div.addEventListener("blur", listener); div.addEventListener("keyup", listener); div.addEventListener("paste", listener); div.addEventListener("copy", listener); div.addEventListener("cut", listener); div.addEventListener("delete", listener); div.addEventListener("mouseup", listener); } var div = document.querySelector("someDiv"); setChangeListener(div, function(event){ console.log(event); });
Я изменил ответ lawwantsin ' s так, и это работает для меня. Я использую событие keyup вместо нажатия клавиши, которое отлично работает.
$('#editor').on('focus', function() { before = $(this).html(); }).on('blur keyup paste', function() { if (before != $(this).html()) { $(this).trigger('change'); } }); $('#editor').on('change', function() {alert('changed')});
вот что сработало для меня:
var clicked = {} $("[contenteditable='true']").each(function(){ var id = $(this).attr("id"); $(this).bind('focus', function() { // store the original value of element first time it gets focus if(!(id in clicked)){ clicked[id] = $(this).html() } }); }); // then once the user clicks on save $("#save").click(function(){ for(var id in clicked){ var original = clicked[id]; var current = $("#"+id).html(); // check if value changed if(original != current) save(id,current); } });
эта тема была очень полезна, пока я изучал эту тему.
Я изменил часть кода, доступного здесь, в плагин jQuery, поэтому он находится в многоразовой форме, в первую очередь для удовлетворения моих потребностей, но другие могут оценить более простой интерфейс для запуска с использованием тегов contenteditable.
https://gist.github.com/3410122
обновление:
из-за своей растущей популярности плагин был принят Makesites.org
развитие будет продолжаться здесь:
вот решение я использовал и работает сказочно. Я использую $(это).text () вместо этого, потому что я просто использую одну строку div, которая является редактируемой. Но вы также можете использовать .html () таким образом, вам не нужно беспокоиться о области глобальной/неглобальной переменной, и ранее фактически прикреплено к редактору div.
$('body').delegate('#editor', 'focus', function(){ $(this).data('before', $(this).html()); }); $('#client_tasks').delegate('.task_text', 'blur', function(){ if($(this).data('before') != $(this).html()){ /* do your stuff here - like ajax save */ alert('I promise, I have changed!'); } });
событие onchange не срабатывает при изменении элемента с атрибутом contentEditable, предлагаемый подход может заключаться в добавлении кнопки в "сохранить" издание.
проверьте этот плагин, который обрабатывает проблему таким образом:
чтобы избежать таймеров и кнопок" сохранить", вы можете использовать событие размытия, которое срабатывает, когда элемент теряет фокус. но чтобы убедиться, что элемент действительно был изменен (а не просто сфокусирован и расфокусирован), его содержимое следует сравнить с его последней версией. или используйте событие keydown, чтобы установить некоторый "грязный" флаг на этом элементе.
С помощью DOMCharacterDataModified под MutationEvents приведет к тому же. Тайм-аут настроен для предотвращения отправки неверных значений (например, в Chrome у меня были некоторые проблемы с пробелом)
var timeoutID; $('[contenteditable]').bind('DOMCharacterDataModified', function() { clearTimeout(timeoutID); $that = $(this); timeoutID = setTimeout(function() { $that.trigger('change') }, 50) }); $('[contentEditable]').bind('change', function() { console.log($(this).text()); })
Я построил плагин 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();
вы также можете удалить / добавить события, если вы хотите
простой ответ в JQuery, я только что создал этот код и думал, что это будет полезно и для других
var cont; $("div [contenteditable=true]").focus(function() { cont=$(this).html(); }); $("div [contenteditable=true]").blur(function() { if ($(this).html()!=cont) { //Here you can write the code to run when the content change } });
два варианта:
1) Для современных (вечнозеленые) браузеры: Событие " input "будет действовать как альтернативное событие" change".
https://developer.mozilla.org/en-US/docs/Web/Events/input
document.querySelector('div').addEventListener('input', (e) => { // Do something with the "change"-like event });
или
<div oninput="someFunc(event)"></div>
или (с помощью jQuery)
$('div').on('click', function(e) { // Do something with the "change"-like event });
2) для учета IE11 и современных (вечнозеленых) браузеров: Это наблюдает за изменениями элементов и их содержимым внутри элемент div.
https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
var div = document.querySelector('div'); var divMO = new window.MutationObserver(function(e) { // Do something on change }); divMO.observe(div, { childList: true, subtree: true, characterData: true });
проверьте эту идею. http://pastie.org/1096892
Я думаю, что это близко. HTML 5 действительно нужно добавить событие изменения в спецификацию. Единственная проблема заключается в том, что функция обратного вызова вычисляет if (before == $(this).html ()) перед фактическим обновлением содержимого в $(this).формат HTML.)( setTimeout не работает, и это печально. Дай мне знать, что ты думаешь.
не JQuery ответ...
function makeEditable(elem){ elem.setAttribute('contenteditable', 'true'); elem.addEventListener('blur', function (evt) { elem.removeAttribute('contenteditable'); elem.removeEventListener('blur', evt.target); }); elem.focus(); }
чтобы использовать его, вызовите (скажем) элемент заголовка с id="myHeader"
makeEditable(document.getElementById('myHeader'))
этот элемент теперь будет редактироваться пользователем, пока он не потеряет фокус.
на основе ответа @balupton:
$(document).on('focus', '[contenteditable]', e => { const self = $(e.target) self.data('before', self.html()) }) $(document).on('blur', '[contenteditable]', e => { const self = $(e.target) if (self.data('before') !== self.html()) { self.trigger('change') } })
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>