Antworten:
Ich würde Anbringen Hörer vorschlagen zu den wichtigsten Veranstaltungen des editierbaren Element gefeuert, obwohl Sie müssen sich bewusst sein , dass keydown
und keypress
Ereignisse ausgelöst werden , bevor der Inhalt selbst geändert wird. Dies deckt nicht alle Möglichkeiten zum Ändern des Inhalts ab: Der Benutzer kann auch das Ausschneiden, Kopieren und Einfügen aus den Menüs Bearbeiten oder Kontextbrowser verwenden, sodass Sie möglicherweise auch die Ereignisse cut
copy
und behandeln möchten paste
. Außerdem kann der Benutzer Text oder anderen Inhalt ablegen, sodass dort ( mouseup
zum Beispiel) mehr Ereignisse vorhanden sind . Möglicherweise möchten Sie den Inhalt des Elements als Fallback abfragen.
UPDATE 29. Oktober 2014
Das HTML5- input
Ereignis ist langfristig die Antwort. Zum Zeitpunkt des Schreibens wird es für contenteditable
Elemente in aktuellen Mozilla- (ab Firefox 14) und WebKit / Blink-Browsern unterstützt, jedoch nicht für IE.
Demo:
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
und paste
Ereignisse in Browsern , die sie unterstützen (IE 5+, Firefox 3.0+, Safari 3+, Chrome)
input
Ereignis abgedeckt werden .
Hier ist eine effizientere Version, die on
für alle inhaltsbearbeitbaren Dateien verwendet wird. Es basiert auf den Top-Antworten hier.
$('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');
}
});
Das Projekt ist hier: https://github.com/balupton/html5edit
document.getElementById('editor_input').innerHTML = 'ssss'
. Nachteil ist, dass es IE11 erfordert
Erwägen Sie die Verwendung von MutationObserver . Diese Beobachter sind entworfen , um Veränderungen in dem DOM und als performant Ersatz zu reagieren Mutationsereignissen .
Vorteile:
Nachteile:
Erfahren Sie mehr:
input
Ereignis (das contenteditable
in allen WebKit- und Mozilla-Browsern unterstützt wird, die Mutationsbeobachter unterstützen), da die DOM-Mutation sowohl über Skripte als auch über Benutzereingaben erfolgen kann, aber es ist eine praktikable Lösung für diese Browser. Ich kann mir vorstellen, dass dies die Leistung mehr beeinträchtigen könnte als das input
Ereignis, aber ich habe keine eindeutigen Beweise dafür.
input
Ereignis in jeder dieser Situationen ausgelöst wird (insbesondere Drag & Drop, Kursivschrift, Kopieren / Ausschneiden / Einfügen über das Kontextmenü). Ich habe auch Fettdruck mit cmd / Strg + B getestet und die erwarteten Ergebnisse erzielt. Ich habe auch überprüft und konnte überprüfen, ob das input
Ereignis nicht bei programmatischen Änderungen ausgelöst wird (was offensichtlich erscheint, aber möglicherweise einer verwirrenden Sprache auf der entsprechenden MDN-Seite widerspricht; siehe unten auf der Seite, um zu sehen, was ich meine: Entwickler .mozilla.org / en-US / docs / Web / Events / Eingabe )
Ich habe die Antwort von lawwantsin so geändert und das funktioniert für mich. Ich benutze das Keyup-Ereignis anstelle des Tastendrucks, was großartig funktioniert.
$('#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')});
non jQuery schnelle und schmutzige Antwort:
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);
});
Zwei Optionen:
1) Für moderne (immergrüne) Browser: Das "Eingabe" -Ereignis würde als alternatives "Änderungs" -Ereignis fungieren.
https://developer.mozilla.org/en-US/docs/Web/Events/input
document.querySelector('div').addEventListener('input', (e) => {
// Do something with the "change"-like event
});
oder
<div oninput="someFunc(event)"></div>
oder (mit jQuery)
$('div').on('click', function(e) {
// Do something with the "change"-like event
});
2) Um IE11 und moderne (immergrüne) Browser zu berücksichtigen: Dies überwacht Elementänderungen und deren Inhalt innerhalb der 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 />
Folgendes hat bei mir funktioniert:
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);
}
});
Dieser Thread war sehr hilfreich, als ich das Thema untersuchte.
Ich habe einen Teil des hier verfügbaren Codes in ein jQuery-Plugin geändert, sodass er in einer wiederverwendbaren Form vorliegt, hauptsächlich um meine Anforderungen zu erfüllen. Andere schätzen jedoch möglicherweise eine einfachere Oberfläche für den Start mit inhaltsbearbeitbaren Tags.
https://gist.github.com/3410122
Aufgrund seiner zunehmenden Beliebtheit wurde das Plugin von Makesites.org übernommen
Die Entwicklung wird von hier aus fortgesetzt:
Hier ist die Lösung, die ich letztendlich verwendet habe und die hervorragend funktioniert. Ich verwende stattdessen $ (this) .text (), weil ich nur ein einzeiliges div verwende, das inhaltlich bearbeitet werden kann. Sie können aber auch .html () verwenden, damit Sie sich keine Gedanken über den Umfang einer globalen / nicht globalen Variablen machen müssen und das Vorherige tatsächlich an den Editor div angehängt ist.
$('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!');
}
});
Um Timer und Schaltflächen zum Speichern zu vermeiden, können Sie ein Unschärfeereignis verwenden, das ausgelöst wird, wenn das Element den Fokus verliert. Um jedoch sicherzugehen, dass das Element tatsächlich geändert wurde (nicht nur fokussiert und defokussiert), sollte sein Inhalt mit seiner letzten Version verglichen werden. Oder verwenden Sie das Keydown-Ereignis, um ein "schmutziges" Flag für dieses Element zu setzen.
Eine einfache Antwort in JQuery: Ich habe diesen Code gerade erstellt und dachte, dass er auch für andere hilfreich sein wird
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]")
alle Kinder eines Div direkt oder indirekt ausgewählt werden, die inhaltsbearbeitbar sind.
Nicht JQuery Antwort ...
function makeEditable(elem){
elem.setAttribute('contenteditable', 'true');
elem.addEventListener('blur', function (evt) {
elem.removeAttribute('contenteditable');
elem.removeEventListener('blur', evt.target);
});
elem.focus();
}
Rufen Sie dazu ein Header-Element mit der ID = "myHeader" auf.
makeEditable(document.getElementById('myHeader'))
Dieses Element kann jetzt vom Benutzer bearbeitet werden, bis es den Fokus verliert.
Das Ereignis onchange wird nicht ausgelöst, wenn ein Element mit dem Attribut contentEditable geändert wird. Ein empfohlener Ansatz könnte darin bestehen, eine Schaltfläche hinzuzufügen, um die Edition zu "speichern" .
Überprüfen Sie dieses Plugin, das das Problem auf diese Weise behandelt:
Die Verwendung von DOMCharacterDataModified unter MutationEvents führt zu demselben Ergebnis . Das Zeitlimit wurde eingerichtet, um das Senden falscher Werte zu verhindern (z. B. hatte ich in Chrome einige Probleme mit der Leertaste).
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
wird nicht ausgelöst, wenn der Benutzer vorhandenen Text ändert, z. B. fett oder kursiv. DOMSubtreeModified
ist in diesem Fall angemessener. Außerdem sollten sich Benutzer daran erinnern, dass ältere Browser diese Ereignisse nicht unterstützen.
Ich habe dazu ein jQuery-Plugin erstellt.
(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);
Sie können einfach anrufen $('.wysiwyg').wysiwygEvt();
Sie können Ereignisse auch entfernen / hinzufügen, wenn Sie dies wünschen
innerHTML
ist teuer). Ich würde empfehlen, das input
Ereignis dort zu verwenden, wo es existiert, und auf so etwas zurückzugreifen, aber mit einer Art Entprellung.
In Angular 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
}
}
Bitte folgen Sie der folgenden einfachen Lösung
In .ts:
getContent(innerText){
this.content = innerText;
}
in .html:
<div (blur)="getContent($event.target.innerHTML)" contenteditable [innerHTML]="content"></div>
Schauen Sie sich diese Idee an. http://pastie.org/1096892
Ich denke es ist nah. HTML 5 muss das Änderungsereignis wirklich zur Spezifikation hinzufügen. Das einzige Problem ist, dass die Rückruffunktion auswertet, ob (vor == $ (this) .html ()), bevor der Inhalt tatsächlich in $ (this) .html () aktualisiert wird. setTimeout funktioniert nicht und es ist traurig. Lass mich wissen was du denkst.
Basierend auf der Antwort von @ 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() { ...}
.