Відповіді:
Я б запропонував приєднати слухачів до ключових подій, запущених редагованим елементом, хоча ви повинні мати на увазі, що keydown
і keypress
події запускаються перед зміною самого вмісту. Це не охоплює всі можливі способи зміни вмісту: користувач також може використовувати вирізати, копіювати та вставляти з меню редагування або контекстного меню браузера, тому ви можете також обробляти 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>
Демонстрація: http://jsfiddle.net/ch6yn/2691/
cut
, copy
і paste
подія в браузерах , які підтримують їх (IE 5 +, Firefox 3.0+, Safari 3+, Chrome)
input
події HTML5 .
Ось більш ефективна версія, яка використовується on
для всіх матеріалів, що містять вміст. Тут засновані основні відповіді.
$('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 та слугувати заміною Mutation Events .
Плюси:
Мінуси:
Вивчайте більше:
input
подія HTML5 (яка підтримується contenteditable
у всіх браузерах WebKit і Mozilla, які підтримують спостерігачів мутацій), оскільки мутація DOM може відбуватися як через скрипт, так і за допомогою введення користувача, але це життєздатне рішення для цих браузерів. Я думаю, що це може зашкодити виступу більше, ніж input
подія, але я не маю твердих доказів для цього.
input
подія HTML5 спрацьовує у кожній із цих ситуацій (зокрема перетягування, курсив, копіювання / вирізання / вставка через контекстне меню). Я також випробував сміливий w / cmd / ctrl + b і отримав очікувані результати. Я також перевірив і зміг переконатися, що input
подія не спрацьовує через програмні зміни (що здається очевидним, але, суперечить, суперечить деякій заплутаній мові на відповідній сторінці MDN; дивіться внизу сторінки тут, щоб побачити, що я маю на увазі: розробник .mozilla.org / en-US / docs / Web / Події / вхід )
Я змінив відповідь законніків так, і це працює для мене. Я використовую подію клавіатури замість натискання клавіші, яка чудово працює.
$('#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) Для сучасних (вічнозелених) браузерів: подія "введення" буде виступати альтернативною подією "зміни".
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, щоб він був у використанні для повторного використання, в першу чергу, щоб задовольнити мої потреби, але інші можуть оцінити більш простий інтерфейс для швидкого запуску, використовуючи змістовні теги.
https://gist.github.com/3410122
Завдяки зростаючій популярності плагін був прийнятий Makesites.org
Розвиток триватиме звідси:
Ось рішення, яке я закінчив використовувати і працює казково. Я використовую натомість $ (this) .text (), тому що я просто використовую одно рядковий div, який може редагувати вміст. Але ви також можете використовувати .html () таким чином, вам не доведеться турбуватися про сферу глобальної / не глобальної змінної, а раніше фактично додається до редактора 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!');
}
});
Щоб уникнути таймерів та кнопок "збереження", ви можете використовувати розмиття подій, що виникає при пожежі, коли елемент втрачає фокус. але щоб бути впевненим, що елемент був фактично змінений (а не просто зосереджений і розфокусований), його вміст слід порівняти з останньою версією. або використовувати подію клавіш, щоб встановити якийсь "брудний" прапор на цьому елементі.
Проста відповідь у 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]")
вибиратимуть всі дитячі диві, прямо чи опосередковано, які можуть бути змістовними.
Відповідь, що не відповідає 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
}
}
Дотримуйтесь наступного простого рішення
В .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() { ...}
.