OnChange событие с contenteditable
Код:
...text <span contenteditable="true" onChange="someFunction()">blah blah</span> text...
Событие onChange не работает. (по крайней мере, в FireFox)
Я не хочу использовать теги textarea/input, потому что должно быть доступно изменение только определенных слов в тексте и должно отображаться в строке (а не в блоке).
Есть ли способ, как это сделать?
Ответы
Ответ 1
Функция, которую я написал:
Один вызов этой функции фиксирует все элементы ContentEditable на странице.
function fix_onChange_editable_elements()
{
var tags = document.querySelectorAll('[contenteditable=true][onChange]');//(requires FF 3.1+, Safari 3.1+, IE8+)
for (var i=tags.length-1; i>=0; i--) if (typeof(tags[i].onblur)!='function')
{
tags[i].onfocus = function()
{
this.data_orig=this.innerHTML;
};
tags[i].onblur = function()
{
if (this.innerHTML != this.data_orig)
this.onchange();
delete this.data_orig;
};
}
}
Ответ 2
Не совсем. Недавние браузеры WebKit поддерживают событие HTML5 input
на contenteditable
, что идеально, но не поддерживается в других браузерах (UPDATE 31 декабря 2012: Firefox поддерживает это с версии 14). В противном случае вы сможете пройти через события мутации DOM DOMNodeInserted
, DOMNodeRemoved
и DOMCharacterDataModified
, но они имеют два недостатка: во-первых, они не поддерживаются в IE < 9 или любой версии Opera для элементов contenteditable
, а во-вторых, новая спецификация с замещающими событиями работает, то есть они, вероятно, будут заменены в будущих браузерах.
Пример в реальном времени: http://jsfiddle.net/MBags/
Или вы можете пойти на более низкий уровень и обрабатывать события клавиш, мыши и буфера обмена (cut
и paste
), которые будут работать во всех основных браузерах, но будут означать, что вам нужно будет проверить, изменился ли изменяемый контент каждый время, когда такое событие срабатывает, которое будет ломаться и вредить пользователю большим количеством контента.
Ответ 3
Я построил плагин 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');
htmlOld = htmlNew;
}
})
})
}
})(jQuery);
Вы можете просто вызвать $('.wysiwyg').wysiwygEvt();
Вы также можете удалить/добавить события, если хотите
Ответ 4
Поскольку элементы, не входящие в элементы ввода, не имеют традиционных событий, связанных с вводом, вам нужно как-то объединить что-то вместе. С этой целью:
var editable = document.querySelectorAll('div[contentEditable]');
for (var i=0, len = editable.length; i<len; i++){
editable[i].setAttribute('data-orig',editable[i].innerHTML);
editable[i].onblur = function(){
if (this.innerHTML == this.getAttribute('data-orig')) {
// no change
}
else {
// change has happened, store new value
this.setAttribute('data-orig',this.innerHTML);
}
};
}
JS Fiddle demo.
Хотя, как отмечено Tim Down, это не должно быть необходимо слишком долго, с очевидным исключением для поддержки старых браузеров.