Ответы:
Я хотел бы предложить , крепящие слушатель ключевых событий обстреляны редактируемым элементом, хотя вы должны знать , что keydownи keypressсобытие вызываются перед само содержанием изменяется. Это не будет охватывать все возможные средства изменения содержания: пользователь может также использовать вырезать, копировать и вставлять текст из Edit или меню контекста браузера, так что вы можете обрабатывать 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>
cut, copyи pasteсобытие в браузерах , которые поддерживают их (IE 5 +, Firefox 3.0+, Safari 3+, Chrome)
inputсобытием HTML5 .
Вот более эффективная версия, которая используется 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
document.getElementById('editor_input').innerHTML = 'ssss'. Недостатком является то, что требуется IE11
Рассмотрите возможность использования MutationObserver . Эти наблюдатели призваны реагировать на изменения в DOM и заменять мутационные события .
Плюсы:
Минусы:
Учить больше:
inputсобытие HTML5 (которое поддерживается contenteditableво всех браузерах WebKit и Mozilla, которые поддерживают наблюдатели мутаций), поскольку мутация DOM может происходить как через сценарий, так и через пользовательский ввод, но это жизнеспособное решение для этих браузеров. Я думаю, что это может повредить производительности больше, чем inputсобытие, но у меня нет веских доказательств этого.
inputсобытие HTML5 возникает в каждой из этих ситуаций (в частности, перетаскивание, выделение курсивом, копирование / вырезание / вставка через контекстное меню). Я также проверил жирный шрифт w / cmd / ctrl + b и получил ожидаемые результаты. Я также проверил и смог убедиться, что inputсобытие не запускается из-за программных изменений (что кажется очевидным, но, возможно, противоречит неясному языку на соответствующей странице MDN; см. Здесь внизу, чтобы понять, что я имею в виду: разработчик .mozilla.org / en-US / docs / Web / Events / input )
Я изменил ответ 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')});
не 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);
});
Два варианта:
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 });
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 />
Вот что сработало для меня:
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 () таким образом, чтобы вам не приходилось беспокоиться о области действия глобальной / неглобальной переменной, а оператор before действительно присоединяется к редактору 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!');
}
});
Чтобы избежать таймеров и кнопок «сохранить», вы можете использовать событие размытия, которое срабатывает, когда элемент теряет фокус. но чтобы быть уверенным, что элемент действительно был изменен (а не только сфокусирован и расфокусирован), его содержимое следует сравнить с его последней версией. или используйте событие keydown, чтобы установить некоторый «грязный» флаг для этого элемента.
Простой ответ в 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
}
});
$("div [contenteditable=true]")будут выбраны все дочерние элементы div, прямо или косвенно, которые являются спорными.
Не 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 не срабатывает при изменении элемента с атрибутом contentEditable, поэтому можно предложить добавить кнопку, чтобы «сохранить» издание.
Проверьте этот плагин, который обрабатывает проблему таким образом:
Использование 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());
})
DOMCharacterDataModifiedне срабатывает, когда пользователь изменяет существующий текст, например, применяя жирный шрифт или курсив. DOMSubtreeModifiedболее уместно в этом случае. Кроме того, люди должны помнить, что устаревшие браузеры не поддерживают эти события.
Я сделал плагин 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();
Вы также можете удалить / добавить события, если хотите
innerHTMLдороже). Я бы порекомендовал использовать inputсобытие там, где оно существует, и прибегнуть к чему-то подобному, но с некоторым видом разоблачения.
В угловых 2+
<div contentEditable (input)="type($event)">
Value
</div>
@Component({
...
})
export class ContentEditableComponent {
...
type(event) {
console.log(event.data) // <-- The pressed key
console.log(event.path[0].innerHTML) // <-- The content of the div
}
}
Пожалуйста, следуйте следующему простому решению
In .ts:
getContent(innerText){
this.content = innerText;
}
в .html:
<div (blur)="getContent($event.target.innerHTML)" contenteditable [innerHTML]="content"></div>
Проверьте эту идею. http://pastie.org/1096892
Я думаю, что это близко. HTML 5 действительно должен добавить событие изменения в спецификацию. Единственная проблема заключается в том, что функция обратного вызова оценивает if (before == $ (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>
document.getElementById("editor").oninput = function() { ...}.