Odpowiedzi:
Sugeruję dołączanie słuchaczy do kluczowych zdarzeń uruchamianych przez element edytowalny, choć musisz pamiętać, że keydown
i keypress
zdarzenia są uruchamiane przed zmianą samej treści. Nie obejmie to wszystkich możliwych sposobów zmiany treści: użytkownik może również używać wycinania, kopiowania i wklejania z menu Edycja lub menu przeglądarki kontekstowej, więc możesz również obsłużyć zdarzenia cut
copy
i paste
. Ponadto użytkownik może upuścić tekst lub inną treść, więc jest tam więcej zdarzeń ( mouseup
na przykład). Możesz sondować zawartość elementu jako awaryjne.
AKTUALIZACJA 29 października 2014 r
HTML5 input
zdarzenie jest odpowiedzią na dłuższą metę. W chwili pisania tego tekstu jest on obsługiwany w contenteditable
elementach obecnych przeglądarek Mozilla (od Firefox 14) i WebKit / Blink, ale nie w IE.
Próbny:
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
a paste
wydarzenia w przeglądarkach, które je obsługują (IE 5+, Firefox 3.0+, Safari 3+, Chrome)
input
zdarzeniem HTML5 .
Oto bardziej wydajna wersja on
dla wszystkich edytowanych treści. Opiera się na najlepszych odpowiedziach tutaj.
$('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');
}
});
Projekt jest tutaj: https://github.com/balupton/html5edit
document.getElementById('editor_input').innerHTML = 'ssss'
. Wadą jest to, że wymaga IE11
Rozważ użycie MutationObserver . Ci obserwatorzy mają za zadanie reagować na zmiany w DOM i zastępować zdarzenia mutacji .
Plusy:
Cons:
Ucz się więcej:
input
zdarzenie HTML5 (które jest obsługiwane contenteditable
we wszystkich przeglądarkach WebKit i Mozilla, które obsługują obserwacje mutacji), ponieważ mutacja DOM może wystąpić zarówno za pomocą skryptu, jak i danych wejściowych użytkownika, ale jest realnym rozwiązaniem dla tych przeglądarek. Wyobrażam sobie, że może to bardziej zaszkodzić wydajności niż samo input
wydarzenie, ale nie mam na to twardych dowodów.
input
zdarzenie HTML5 jest uruchamiane w każdej z tych sytuacji (w szczególności przeciąganie i upuszczanie, kursywa, kopiowanie / wycinanie / wklejanie za pomocą menu kontekstowego). Przetestowałem również pogrubienie w / cmd / ctrl + b i uzyskałem oczekiwane wyniki. Sprawdziłem również i byłem w stanie sprawdzić, czy input
zdarzenie nie uruchamia się przy zmianach programowych (co wydaje się oczywiste, ale prawdopodobnie jest sprzeczne z jakimś mylącym językiem na odpowiedniej stronie MDN; zobacz dół strony tutaj, aby zobaczyć, co mam na myśli: programista .mozilla.org / en-US / docs / Web / Events / input )
Zmodyfikowałem odpowiedź prawnika w ten sposób i to działa dla mnie. Używam zdarzenia keyup zamiast naciśnięcia klawisza, co działa świetnie.
$('#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')});
szybka i brudna odpowiedź 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);
});
Dwie opcje:
1) W przypadku nowoczesnych (wiecznie zielonych) przeglądarek: zdarzenie „wejściowe” działałoby jako alternatywne zdarzenie „zmiany”.
https://developer.mozilla.org/en-US/docs/Web/Events/input
document.querySelector('div').addEventListener('input', (e) => {
// Do something with the "change"-like event
});
lub
<div oninput="someFunc(event)"></div>
lub (z jQuery)
$('div').on('click', function(e) {
// Do something with the "change"-like event
});
2) Aby uwzględnić IE11 i nowoczesne (wiecznie zielone) przeglądarki: Obserwuje zmiany elementów i ich zawartość w 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 />
Oto, co zadziałało dla mnie:
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);
}
});
Ten wątek był bardzo pomocny podczas badania tematu.
Zmodyfikowałem część kodu dostępnego tutaj w wtyczce jQuery, więc jest w formie wielokrotnego użytku, przede wszystkim w celu zaspokojenia moich potrzeb, ale inni mogą docenić prostszy interfejs do uruchamiania za pomocą tagów, które można zadowolić.
https://gist.github.com/3410122
Ze względu na rosnącą popularność wtyczka została przyjęta przez Makesites.org
Rozwój będzie kontynuowany stąd:
Oto rozwiązanie, z którego korzystałem i działa bajecznie. Zamiast tego używam $ (this) .text (), ponieważ po prostu używam div jednowierszowego, który można edytować treści. Ale możesz także użyć .html () w ten sposób, że nie musisz się martwić o zakres globalnej / nieglobalnej zmiennej, a wcześniejsza wersja faktycznie jest dołączona do edytora 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!');
}
});
Aby uniknąć liczników czasu i przycisków „zapisz”, możesz użyć zdarzenia rozmycia, które uruchamia się, gdy element traci fokus. ale aby mieć pewność, że element został faktycznie zmieniony (nie tylko skupiony i nieostry), jego zawartość należy porównać z jego ostatnią wersją. lub użyj zdarzenia keydown, aby ustawić flagę „brudną” dla tego elementu.
Prosta odpowiedź w JQuery, właśnie stworzyłem ten kod i pomyślałem, że będzie on pomocny także dla innych
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]")
wybierze wszystkie dzieci div, bezpośrednio lub pośrednio, które są zadowolone.
Odpowiedź nie JQuery ...
function makeEditable(elem){
elem.setAttribute('contenteditable', 'true');
elem.addEventListener('blur', function (evt) {
elem.removeAttribute('contenteditable');
elem.removeEventListener('blur', evt.target);
});
elem.focus();
}
Aby go użyć, wywołaj (powiedzmy) element nagłówka o id = "myHeader"
makeEditable(document.getElementById('myHeader'))
Ten element będzie teraz edytowalny przez użytkownika, dopóki nie straci ostrości.
Zdarzenie onchange nie jest uruchamiane po zmianie elementu z atrybutem contentEditable. Sugerowanym podejściem może być dodanie przycisku w celu „zapisania” edycji.
Sprawdź tę wtyczkę, która rozwiązuje problem w ten sposób:
Użycie DOMCharacterDataModified pod MutationEvents doprowadzi do tego samego. Limit czasu jest skonfigurowany, aby zapobiec wysyłaniu niepoprawnych wartości (np. W Chrome miałem problemy z klawiszem spacji)
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
nie będzie uruchamiany, gdy użytkownik zmodyfikuje istniejący tekst, na przykład stosując pogrubienie lub kursywę. DOMSubtreeModified
jest bardziej odpowiednie w tym przypadku. Ludzie powinni także pamiętać, że starsze przeglądarki nie obsługują tych zdarzeń.
W tym celu zbudowałem wtyczkę 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);
Możesz po prostu zadzwonić $('.wysiwyg').wysiwygEvt();
Możesz także usunąć / dodać wydarzenia, jeśli chcesz
innerHTML
jest droga). Poleciłbym wykorzystać input
wydarzenie tam, gdzie ono istnieje i powrócić do czegoś takiego, ale z pewnym zapowiedziami.
W 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
}
}
Postępuj zgodnie z następującym prostym rozwiązaniem
W .ts:
getContent(innerText){
this.content = innerText;
}
w .html:
<div (blur)="getContent($event.target.innerHTML)" contenteditable [innerHTML]="content"></div>
Sprawdź ten pomysł. http://pastie.org/1096892
Myślę, że jest blisko. HTML 5 naprawdę musi dodać zdarzenie zmiany do specyfikacji. Jedynym problemem jest to, że funkcja zwrotna ocenia, czy (przed == $ (this) .html ()) przed faktyczną aktualizacją treści w $ (this) .html (). setTimeout nie działa i to smutne. Powiedz mi co myślisz.
Na podstawie odpowiedzi @ 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() { ...}
.