события изменения contenteditable
Я хочу, чтобы запустить функцию, когда пользователь редактирует содержимое div
с
17 ответов
Я бы предложил прикрепить слушателей к ключевым событиям, вызванным редактируемым элементом, хотя вам нужно знать, что keydown
и keypress
события запускаются до изменения самого содержимого. Это не будет охватывать все возможные способы изменения содержимого: пользователь также может использовать вырезать, копировать и вставлять из меню редактирования или контекстного браузера, поэтому вы можете обработать cut
copy
и paste
слишком событий. Кроме того, пользователь может удалить текст или другой контент, поэтому там больше событий (mouseup
, например). Возможно, вы захотите опросить содержимое элемента в качестве резервного.
обновление 29 октября 2014
на в 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 и в качестве замены исполнителя на Событий Мутации.
плюсы:
- пожары любой изменение происходит, что трудно достичь, слушая ключевые события, как это предлагается другими ответами. Например, все это хорошо работает: drag & drop, курсив, копирование/вырезание / вставка через контекст меню.
- разработанный с учетом производительности.
- простой, понятный код. Гораздо проще понять и отладить код, который слушает одно событие, а не код, который слушает 10 событий.
- Google имеет отличный библиотека резюме мутаций что делает использование MutationObservers очень простым.
плюсы:
- требуется последняя версия Firefox (14.0+), Chrome (18+) или IE (11+).
- новый API для понимания
- не много информации о лучших практик и кейсов
подробнее:
- Я написал немного фрагмент для сравнения использования MutationObserers для обработки различных событий. Я использовал код balupton с его ответ имеет большинство upvotes.
- Mozilla имеет отличную страницу на API
- взгляните на the 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 так, и это работает для меня. Я использую событие 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
развитие будет продолжаться здесь:
вот решение, которое я использовал и работает сказочно. Я использую $(this).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 не работает, и это грустно. Дай мне знать, что ты думаешь.
Non 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>