web-dev-qa-db-ja.com

満足できる変更イベント

ユーザーがdiv属性でcontenteditableの内容を編集したときに関数を実行したいのですが。 onchangeイベントと同等のものは何ですか?

私はjQueryを使用しているので、jQueryを使用するすべてのソリューションが優先されます。ありがとうございます。

317
Jourkey

keydownname__イベントとkeypressname__イベントはコンテンツ自体が変更される前に起動されることに注意する必要がありますが、編集可能な要素によって起動されるキーイベントにリスナーを添付することをお勧めします。ユーザーが編集、コンテキストブラウザのメニューから切り取り、コピー、貼り付けを使用することもできるので、cutname__、copyname__、pastename__の各イベントも処理することをお勧めします。また、ユーザーはテキストや他のコンテンツをドロップすることができるので、そこにはさらにイベントがあります(たとえば、mouseupname__)。フォールバックとして要素の内容をポーリングすることをお勧めします。

更新2014年10月29日

HTML5 inputname__イベント は、長期的には答えです。これを書いている時点では、現在のMozilla(Firefox 14以降)およびWebKit/Blinkブラウザのcontenteditablename__要素ではサポートされていますが、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/

262
Tim Down

これは、すべてのコンテンツに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

176
balupton

MutationObserver の使用を検討してください。これらのオブザーバはDOMの変更に反応するように、そして Mutation Events の代わりになるように設計されています。

長所:

  • 何らかのの変更が発生したときに発生します。他の回答で示唆されているように、重要なイベントをリスニングすることによって達成するのは困難です。たとえば、これらすべてはうまく機能します。ドラッグ&ドロップ、イタリック体、コンテキストメニューからのコピー/切り取り/貼り付けです。
  • パフォーマンスを念頭に置いて設計されています。
  • シンプルでわかりやすいコード。 10個のイベントを監視するコードよりも、1つのイベントを監視するコードを理解してデバッグする方がはるかに簡単です。
  • Googleには優れた 変異サマリライブラリ があり、MutationObserversを非常に簡単に使用できます。

短所:

  • 最新バージョンのFirefox(14.0以降)、Chrome(18以降)、またはIE(11+)が必要です。
  • 理解する新しいAPI
  • ベストプラクティスやケーススタディに関する情報はまだ多くありません

もっと詳しく知る:

  • MutationObserersを使ってさまざまなイベントを処理することを比較するために、少し 断片 を書きました。彼の answer が最も支持を得ているので、私はbaluptonのコードを使いました。
  • 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の答えをそのように修正しました、そしてこれは私のために働きます。私はkeypressの代わりに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')});
20
Dennkster

2つの選択肢:

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

私が主題を調査している間、このスレッドは非常に役に立ちました。

ここで利用可能なコードの一部をjQueryプラグインに変更したので、主に私のニーズを満たすために再利用可能な形式になっています。

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

これが私が使用してしまった解決策であり、素晴らしく機能します。内容を編集できる1行のdivを使用しているだけなので、代わりに$(this).text()を使用します。しかし、グローバル/非グローバル変数のスコープを気にする必要はなく、以前は実際にはエディタのdivに添付されているので、.html()を使用することもできます。

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

タイマーや「保存」ボタンを避けるために、要素がフォーカスを失ったときに発生するブラーイベントを使用することができます。しかし、要素が実際に変更されたことを確実にするために(焦点を絞ったり、焦点をぼかしたりしているだけではありません)、その内容を最後のバージョンと比較する必要があります。またはkeydownイベントを使ってこの要素に "dirty"フラグを設定してください。

0
joox

MutationEventsの下のDOMCharacterDataModified を使用すると同じ結果になります。タイムアウトは、誤った値を送信しないように設定されています(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

ContentEditable属性を持つ要素が変更されてもonchangeイベントは発生しません。推奨される方法は、ボタンを追加して "save"にすることです。版。

そのように問題を処理するこのプラグインをチェックしてください:

0
CMS