события изменения contenteditable
Я хочу, чтобы запустить функцию, когда пользователь редактирует содержимое div с
17 ответов:
Я бы предложил прикреплять слушателей к ключевым событиям, вызванным редактируемым элементом, хотя вам нужно знать, что
keydownиkeypressсобытия запускаются до изменения самого содержимого. Это не будет охватывать все возможные способы изменения содержимого: пользователь также может использовать вырезать, копировать и вставлять из меню редактирования или контекстного браузера, поэтому вы можете обрабатыватьcutcopyи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>