Ответы:
Я хотел бы предложить , крепящие слушатель ключевых событий обстреляны редактируемым элементом, хотя вы должны знать , что 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() { ...}
.