Risposte:
Io suggerirei di ascoltatori connessi a eventi chiave sparato dall'elemento modificabile, anche se è necessario essere consapevoli del fatto che keydown
e keypress
eventi vengono generati prima che il contenuto stesso è cambiato. Questo non coprirà tutti i mezzi possibili per cambiare il contenuto: l'utente può anche usare taglia, copia e incolla dai menu del browser Modifica o contestuale, quindi potresti voler gestire anche gli eventi cut
copy
e paste
. Inoltre, l'utente può rilasciare testo o altri contenuti, quindi ci sono più eventi lì ( mouseup
, ad esempio). Potresti voler eseguire il polling del contenuto dell'elemento come fallback.
AGGIORNAMENTO 29 ottobre 2014
L' evento HTML5input
è la risposta a lungo termine. Al momento della stesura, è supportato per contenteditable
elementi negli attuali browser Mozilla (da Firefox 14) e WebKit / Blink, ma non 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
e paste
gli eventi nei browser che li supportano (IE 5+, Firefox 3.0+, Safari 3+, Chrome)
input
dall'evento HTML5 .
Ecco una versione più efficiente che utilizza on
per tutti gli contenteditables. Si basa sulle risposte migliori qui.
$('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');
}
});
Il progetto è qui: https://github.com/balupton/html5edit
document.getElementById('editor_input').innerHTML = 'ssss'
. Lo svantaggio è che richiede IE11
Prendi in considerazione l'utilizzo di MutationObserver . Questi osservatori sono progettati per reagire ai cambiamenti nel DOM e in sostituzione degli eventi di mutazione .
Professionisti:
Contro:
Per saperne di più:
input
dell'evento HTML5 (che è supportato contenteditable
in tutti i browser WebKit e Mozilla che supportano gli osservatori di mutazione), poiché la mutazione DOM potrebbe verificarsi tramite script e input dell'utente, ma è una soluzione praticabile per quei browser. Immagino che potrebbe danneggiare le prestazioni più input
dell'evento, ma non ho prove concrete per questo.
input
evento HTML5 si attiva in ognuna di queste situazioni (in particolare trascinamento della selezione, corsivo, copia / taglia / incolla attraverso il menu contestuale). Ho anche testato il grassetto w / cmd / ctrl + b e ho ottenuto i risultati previsti. Ho anche controllato e sono stato in grado di verificare che l' input
evento non si attiva su modifiche programmatiche (il che sembra ovvio, ma è probabilmente contrario a un linguaggio confuso sulla pagina MDN pertinente; vedi il fondo della pagina qui per vedere cosa intendo: sviluppatore .mozilla.org / it-US / docs / Web / Events / input )
Ho modificato la risposta di Lawwantsin in questo modo e questo funziona per me. Uso l'evento keyup invece di keypress che funziona alla grande.
$('#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')});
risposta rapida e sporca 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);
});
Due opzioni:
1) Per i browser moderni (sempreverdi): l'evento "input" fungerebbe da evento alternativo "change".
https://developer.mozilla.org/en-US/docs/Web/Events/input
document.querySelector('div').addEventListener('input', (e) => {
// Do something with the "change"-like event
});
o
<div oninput="someFunc(event)"></div>
o (con jQuery)
$('div').on('click', function(e) {
// Do something with the "change"-like event
});
2) Per tenere conto di IE11 e dei browser moderni (sempreverdi): controlla i cambiamenti degli elementi e il loro contenuto all'interno del 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 />
Ecco cosa ha funzionato per me:
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);
}
});
Questo thread è stato molto utile mentre stavo indagando sull'argomento.
Ho modificato parte del codice disponibile qui in un plug-in jQuery, quindi è in una forma riutilizzabile, principalmente per soddisfare le mie esigenze, ma altri potrebbero apprezzare un'interfaccia più semplice per iniziare a utilizzare tag contenteditable.
https://gist.github.com/3410122
A causa della sua crescente popolarità, il plugin è stato adottato da Makesites.org
Lo sviluppo continuerà da qui:
Ecco la soluzione che ho finito per usare e funziona favolosamente. Uso $ (this) .text () invece perché sto solo usando un div di una riga che è modificabile nel contenuto. Ma puoi anche usare .html () in questo modo non devi preoccuparti dell'ambito di una variabile globale / non globale e il precedente è effettivamente collegato al div editor.
$('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!');
}
});
Per evitare timer e pulsanti "salva", è possibile utilizzare l'evento sfocatura che si attiva quando l'elemento perde lo stato attivo. ma per essere sicuri che l'elemento sia stato effettivamente modificato (non solo focalizzato e sfocato), il suo contenuto dovrebbe essere confrontato con la sua ultima versione. oppure usa l'evento keydown per impostare un flag "sporco" su questo elemento.
Una semplice risposta in JQuery, ho appena creato questo codice e ho pensato che sarebbe stato utile anche per gli altri
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]")
selezionerà tutti i bambini di un div, direttamente o indirettamente, che sono contenti.
Risposta non JQuery ...
function makeEditable(elem){
elem.setAttribute('contenteditable', 'true');
elem.addEventListener('blur', function (evt) {
elem.removeAttribute('contenteditable');
elem.removeEventListener('blur', evt.target);
});
elem.focus();
}
Per usarlo, chiama (diciamo) un elemento header con id = "myHeader"
makeEditable(document.getElementById('myHeader'))
Quell'elemento sarà ora modificabile dall'utente fino a quando non perde lo stato attivo.
L'evento onchange non si attiva quando viene modificato un elemento con l'attributo contentEditable, un approccio suggerito potrebbe essere quello di aggiungere un pulsante, per "salvare" l'edizione.
Controlla questo plugin che gestisce il problema in questo modo:
L'uso di DOMCharacterDataModified in MutationEvents porterà allo stesso. Il timeout è impostato per impedire l'invio di valori errati (ad es. In Chrome ho avuto alcuni problemi con la chiave dello spazio)
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
non si attiva quando l'utente modifica il testo esistente, ad esempio applicando grassetto o corsivo. DOMSubtreeModified
è più appropriato in questo caso. Inoltre, le persone dovrebbero ricordare che i browser legacy non supportano questi eventi.
Ho creato un plugin jQuery per farlo.
(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);
Puoi semplicemente chiamare $('.wysiwyg').wysiwygEvt();
Se lo desideri, puoi anche rimuovere / aggiungere eventi
innerHTML
è costoso). Consiglierei di utilizzare l' input
evento in cui esiste e di tornare a qualcosa del genere ma con una sorta di rimbalzo.
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
}
}
Segui la seguente semplice soluzione
In .ts:
getContent(innerText){
this.content = innerText;
}
in .html:
<div (blur)="getContent($event.target.innerHTML)" contenteditable [innerHTML]="content"></div>
Dai un'occhiata a questa idea. http://pastie.org/1096892
Penso che sia vicino. HTML 5 deve davvero aggiungere l'evento change alle specifiche. L'unico problema è che la funzione di callback valuta se (prima == $ (questo) .html ()) prima che il contenuto sia effettivamente aggiornato in $ (questo) .html (). setTimeout non funziona ed è triste. Fatemi sapere cosa ne pensate.
Basato sulla risposta di @ 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() { ...}
.