it-swarm.com.ru

оспариваемые события изменения

Я хочу запустить функцию, когда пользователь редактирует содержимое div с атрибутом contenteditable. Что эквивалентно событию onchange?

Я использую jQuery, поэтому любые решения, использующие jQuery, предпочтительнее. Спасибо!

307
Jourkey

Я бы предложил присоединить слушателей к ключевым событиям, инициируемым редактируемым элементом, хотя вы должны знать, что события keydown и keypress запускаются до изменения самого содержимого. Это не будет охватывать все возможные способы изменения содержимого: пользователь также может использовать вырезание, копирование и вставку из меню редактирования или контекстного браузера, поэтому вы можете также обрабатывать события cutcopy и 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/

249
Tim Down

Вот более эффективная версия, которая использует on для всех contenteditables. Это основано на лучших ответах здесь.

$('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

173
balupton

Попробуйте использовать MutationObserver . Эти наблюдатели предназначены для реагирования на изменения в DOM, а также как замену событиям мутации .

Плюсы:

  • Возникает, когда происходит любое изменение, чего трудно достичь, прослушивая ключевые события, как это предусмотрено другими ответами. Например, все это хорошо работает: перетаскивание, выделение курсивом, копирование/вырезание/вставка через контекстное меню.
  • Разработанный с учетом производительности.
  • Простой, понятный код. Намного проще понять и отладить код, который слушает одно событие, а не код, который слушает 10 событий.
  • Google имеет превосходную библиотеку сводок мутаций , которая делает использование MutationObservers очень простым.

Минусы:

  • Требуется последняя версия Firefox (14.0+), Chrome (18+) или IE (11+).
  • Новый API для понимания
  • Пока не доступно много информации о лучших практиках или тематических исследованиях

Учить больше:

  • Я написал небольшой фрагмент , чтобы сравнить использование MutationObserers для обработки различных событий. Я использовал код Балуптона, так как его ответ имеет наибольшее количество голосов.
  • Mozilla имеет отличную страницу по API
  • Взгляните на MutationSummary библиотеку
49
jrullmann

не 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);
});
20
Developia

Я изменил ответ Lawwantsin так, и это работает для меня. Я использую событие keyup вместо нажатия клавиши, которая прекрасно работает.

$('#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')});
19
Dennkster

Эта тема была очень полезна, пока я изучал эту тему. 

Я изменил часть кода, доступного здесь, в плагин jQuery, чтобы он имел форму многократного использования, в первую очередь для удовлетворения моих потребностей, но другие могут оценить более простой интерфейс для быстрого запуска с использованием тегов contenteditable. 

https://Gist.github.com/3410122

Обновление:

В связи с растущей популярностью плагин был принят Makesites.org

Развитие будет продолжено отсюда:

https://github.com/makesites/jquery-contenteditable

3
tracend

Вот что сработало для меня:

   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);
            }
   });
3
gregory whiteside

Два варианта:

1) Для современных (вечнозеленых) браузеров: Событие «input» будет действовать как альтернативное событие «change».

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 });
2
bit-less

Вот решение, которое я в итоге использовал и работает сказочно. Вместо этого я использую $ (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!');
    }
});
2
user740433

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 />

1
superwf

Чтобы избежать таймеров и кнопок «сохранить», вы можете использовать событие размытия, которое срабатывает, когда элемент теряет фокус. но чтобы быть уверенным, что элемент действительно был изменен (а не только сфокусирован и расфокусирован), его содержимое следует сравнить с его последней версией. или используйте событие keydown, чтобы установить некоторый «грязный» флаг для этого элемента.

0
joox

Использование 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());
})

пример JSFIDDLE

0
janfabian

Простой ответ в 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
        }           
    });
0
sarath

Не 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'))

Этот элемент теперь будет редактироваться пользователем, пока он не потеряет фокус.

0
DrMcCleod

Я сделал плагин 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();

Вы также можете удалить/добавить события, если хотите

0
Blowsie

Событие onchange не срабатывает при изменении элемента с атрибутом contentEditable, поэтому можно предложить добавить кнопку, чтобы "сохранить" издание.

Проверьте этот плагин, который обрабатывает проблему таким образом:

0
CMS