Jawaban:
Saya sarankan melampirkan pendengar ke acara utama yang dipecat oleh elemen yang dapat diedit, meskipun Anda harus menyadari itu keydown
dan keypress
acara dipecat sebelum kontennya diubah. Ini tidak akan mencakup segala cara yang mungkin untuk mengubah konten: pengguna juga dapat menggunakan memotong, menyalin, dan menempel dari menu browser Edit atau konteks, sehingga Anda mungkin ingin menangani cut
copy
dan paste
acara juga. Selain itu, pengguna dapat menjatuhkan teks atau konten lain, sehingga ada lebih banyak acara di sana ( mouseup
, misalnya). Anda mungkin ingin mensurvei konten elemen sebagai fallback.
PEMBARUAN 29 Oktober 2014
The HTML5 input
acara adalah jawaban dalam jangka panjang. Pada saat penulisan, ini didukung untuk contenteditable
elemen dalam Mozilla saat ini (dari Firefox 14) dan browser WebKit / Blink, tetapi tidak untuk 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
dan paste
acara di browser yang mendukungnya (IE 5+, Firefox 3.0+, Safari 3+, Chrome)
input
acara HTML5 .
Ini adalah versi yang lebih efisien yang digunakan on
untuk semua konten yang dapat diedit. Ini didasarkan dari jawaban teratas di sini.
$('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');
}
});
Proyeknya ada di sini: https://github.com/balupton/html5edit
document.getElementById('editor_input').innerHTML = 'ssss'
. Kekurangannya adalah itu membutuhkan
Pertimbangkan menggunakan MutationObserver . Pengamat ini dirancang untuk bereaksi terhadap perubahan DOM, dan sebagai pengganti pemain untuk Acara Mutasi .
Pro:
Cons:
Belajarlah lagi:
input
acara HTML5 (yang didukung untuk contenteditable
semua browser WebKit dan Mozilla yang mendukung pengamat mutasi), karena mutasi DOM dapat terjadi melalui skrip serta input pengguna, tetapi ini merupakan solusi yang layak untuk browser tersebut. Saya membayangkan itu bisa merusak kinerja lebih dari input
peristiwa itu juga, tetapi saya tidak punya bukti kuat untuk ini.
input
acara HTML5 menyala di setiap situasi ini (khusus seret & jatuhkan, miringkan, salin / potong / tempel melalui menu konteks). Saya juga menguji huruf tebal w / cmd / ctrl + b dan mendapatkan hasil yang diharapkan. Saya juga memeriksa dan dapat memverifikasi bahwa input
acara tersebut tidak memicu perubahan terprogram (yang tampak jelas, tetapi bisa dibilang bertentangan dengan beberapa bahasa membingungkan pada halaman MDN yang relevan; lihat bagian bawah halaman di sini untuk melihat apa yang saya maksud: pengembang .mozilla.org / en-US / docs / Web / Acara / input )
Saya telah mengubah jawaban lawwantsin seperti itu dan ini bekerja untuk saya. Saya menggunakan acara keyup bukan penekanan tombol yang berfungsi dengan baik.
$('#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 jawaban cepat dan kotor :
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);
});
Dua pilihan:
1) Untuk browser modern (evergreen): Acara "input" akan bertindak sebagai acara "perubahan" alternatif.
https://developer.mozilla.org/en-US/docs/Web/Events/input
document.querySelector('div').addEventListener('input', (e) => {
// Do something with the "change"-like event
});
atau
<div oninput="someFunc(event)"></div>
atau (dengan jQuery)
$('div').on('click', function(e) {
// Do something with the "change"-like event
});
2) Untuk menjelaskan browser IE11 dan modern (evergreen): Ini mengawasi perubahan elemen dan isinya di dalam 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 />
Inilah yang bekerja untuk saya:
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);
}
});
Utas ini sangat membantu saat saya menyelidiki masalah ini.
Saya telah memodifikasi beberapa kode yang tersedia di sini menjadi plugin jQuery sehingga itu dalam bentuk yang dapat digunakan kembali, terutama untuk memenuhi kebutuhan saya tetapi yang lain mungkin menghargai antarmuka yang lebih sederhana untuk memulai dengan menggunakan tag yang dapat diedit.
https://gist.github.com/3410122
Karena popularitasnya yang semakin meningkat, plugin ini telah diadopsi oleh Makesites.org
Pengembangan akan berlanjut dari sini:
Inilah solusi yang akhirnya saya gunakan dan bekerja dengan luar biasa. Saya menggunakan $ (this) .text () sebagai gantinya karena saya hanya menggunakan satu baris div yang dapat diedit konten. Tetapi Anda juga dapat menggunakan .html () dengan cara ini Anda tidak perlu khawatir tentang ruang lingkup variabel global / non-global dan sebelumnya benar-benar dilampirkan ke editor 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!');
}
});
Untuk menghindari penghitung waktu dan tombol "simpan", Anda dapat menggunakan acara blur yang menyala ketika elemen kehilangan fokus. tetapi untuk memastikan bahwa elemen tersebut benar-benar diubah (tidak hanya fokus dan tidak fokus), isinya harus dibandingkan dengan versi terakhirnya. atau gunakan acara keydown untuk mengatur beberapa bendera "kotor" pada elemen ini.
Sebuah jawaban sederhana di JQuery, saya baru saja membuat kode ini dan berpikir itu akan bermanfaat bagi orang lain juga
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]")
akan memilih semua anak dari div, secara langsung atau tidak langsung, yang dapat diedit.
Bukan jawaban JQuery ...
function makeEditable(elem){
elem.setAttribute('contenteditable', 'true');
elem.addEventListener('blur', function (evt) {
elem.removeAttribute('contenteditable');
elem.removeEventListener('blur', evt.target);
});
elem.focus();
}
Untuk menggunakannya, panggil (katakanlah) elemen tajuk dengan id = "myHeader"
makeEditable(document.getElementById('myHeader'))
Elemen itu sekarang akan dapat diedit oleh pengguna sampai kehilangan fokus.
Acara onchange tidak menyala ketika elemen dengan atribut contentEditable diubah, pendekatan yang disarankan bisa dengan menambahkan tombol, untuk "menyimpan" edisi.
Periksa plugin ini yang menangani masalah dengan cara itu:
Menggunakan DOMCharacterDataModified di bawah MutationEvents akan mengarah ke hal yang sama. Batas waktu disetel untuk mencegah pengiriman nilai yang salah (mis. Di Chrome saya mengalami beberapa masalah dengan tombol spasi)
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
tidak akan diaktifkan ketika pengguna memodifikasi teks yang ada, misalnya menerapkan cetak tebal atau miring. DOMSubtreeModified
lebih tepat dalam hal ini. Selain itu, orang harus ingat bahwa browser lama tidak mendukung acara ini.
Saya membangun plugin jQuery untuk melakukan ini.
(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);
Anda cukup menelepon $('.wysiwyg').wysiwygEvt();
Anda juga dapat menghapus / menambah acara jika diinginkan
innerHTML
mahal). Saya akan merekomendasikan menggunakan input
acara di mana itu ada dan jatuh kembali ke sesuatu seperti ini tetapi dengan semacam debouncing.
Dalam 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
}
}
Silakan ikuti solusi sederhana berikut ini
Dalam .ts:
getContent(innerText){
this.content = innerText;
}
dalam .html:
<div (blur)="getContent($event.target.innerHTML)" contenteditable [innerHTML]="content"></div>
Lihat ide ini. http://pastie.org/1096892
Saya pikir sudah dekat. HTML 5 benar-benar perlu menambahkan acara perubahan ke spec. Satu-satunya masalah adalah bahwa fungsi callback mengevaluasi if (before == $ (this) .html ()) sebelum konten benar-benar diperbarui dalam $ (this) .html (). setTimeout tidak berfungsi, dan itu menyedihkan. Biarkan aku tahu apa yang Anda pikirkan.
Berdasarkan jawaban @ 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() { ...}
.