Довольные события изменений
-
21-09-2019 - |
Вопрос
Я хочу запустить функцию, когда пользователь редактирует содержание div
с contenteditable
атрибут. Что такое эквивалент onchange
мероприятие?
Я использую jQuery, поэтому любые решения, которые используют jQuery, предпочтительнее. Спасибо!
Решение
Я бы посоветовал прикрепить слушателей к ключевым событиям, запущенным редактируемым элементом, хотя вам нужно знать, что keydown
а также keypress
События запущены до того, как сам контент будет изменен. Это не будет охватывать все возможные средства изменения контента: пользователь также может использовать вырезание, копирование и вставку из меню браузера редактирования или контекста, чтобы вы могли обработать cut
copy
а также paste
События тоже. Кроме того, пользователь может сбросить текст или другой контент, поэтому там больше событий (mouseup
, Например). Вы можете захотеть опросить содержимое элемента как запасную сторону.
Обновление 29 октября 2014 г.
А HTML5 input
мероприятие это ответ в долгосрочной перспективе. На момент написания он поддерживается contenteditable
Элементы в нынешних мозилле (из Firefox 14) и Webkit/Blink Browsers, но не IE.
Демонстрация:
document.getElementById("editor").addEventListener("input", function() {
console.log("input event fired");
}, false);
<div contenteditable="true" id="editor">Please type something in here</div>
Демонстрация: http://jsfiddle.net/ch6yn/2691/
Другие советы
Вот более эффективная версия, которая использует on
для всех довольных. Он основан на верхних ответах здесь.
$('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 для обработки различных событий. Я использовал код Балуптона с его отвечать Имеет наиболее подъем.
- Мозилла имеет отличную страницу на API
- Взглянуть на Mutationsummary библиотека
не 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 вместо Keypress, которое отлично работает.
$('#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')});
const p = document.querySelector('p')
const result = document.querySelector('div')
const observer = new MutationObserver((mutationRecords) => {
result.textContent = mutationRecords[0].target.data
// result.textContent = p.textContent
})
observer.observe(p, {
characterData: true,
subtree: true,
})
<p contenteditable>abc</p>
<div />
Два варианта:
1) Для современных (вечнозеленых) браузеров:Событие «Вход» будет действовать как альтернативное событие «Изменение».
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/mutebserver
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 });
Вот что сработало для меня:
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, так что он находится в повторной форме, в первую очередь для удовлетворения моих потребностей, но другие могут оценить более простой интерфейс для Jumpstart с использованием довольных тегов.
https://gist.github.com/3410122
Обновлять:
Из -за растущей популярности плагин был принят Makeites.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!');
}
});
Без 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'))
Этот элемент теперь будет редактирован пользователем, пока не потеряет фокус.
Событие OnChange не стреляет, когда изменяется элемент с атрибутом с довольным, предложенным подходом может быть добавление кнопки, в "спасти" издание.
Проверьте этот плагин, который решает проблему таким образом:
Чтобы избежать таймеров и кнопок «Сохранить», вы можете использовать размытое событие, когда стреляет, когда элемент теряет фокус. Но чтобы быть уверенным, что элемент был фактически изменен (не только сфокусирован и дефокус), его содержание следует сравнить с его последней версией. Или используйте событие 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
}
});
Проверьте эту идею.http://pastie.org/1096892
Я думаю, что это близко. HTML 5 действительно должен добавить событие изменения в спецификацию. Единственная проблема заключается в том, что функция обратного вызова оценивает if (до == $ (this) .html ()) до того, как контент фактически обновляется в $ (this) .html (). Settimeout не работает, и это грустно. Дайте мне знать, что вы думаете.
Основано на ответе @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>