Question

Je veux exécuter une fonction lorsqu'un utilisateur modifie le contenu d'un div avec attribut contenteditable. Quel est l'équivalent d'un événement onchange?

J'utilise jQuery donc des solutions qui utilise jQuery est préférée. Merci!

Était-ce utile?

La solution

Je vous suggère de fixer les auditeurs à des événements clés tirés par l'élément modifiable, bien que vous devez être conscient que les événements de keydown et keypress sont tirées avant que le contenu lui-même est changé. Cela ne couvre pas tous les moyens de modifier le contenu: l'utilisateur peut utiliser également couper, copier et coller des menus du navigateur Modifier ou contexte, vous voudrez peut-être gérer la cut de copy et les événements paste aussi. En outre, l'utilisateur peut déposer du texte ou tout autre contenu, donc il là d'autres événements sont (mouseup, par exemple). Vous pouvez interroger le contenu de l'élément comme solution de repli.

Octobre 2014 changement 29

Le événement HTML5 input est la réponse le long terme. Au moment de l'écriture, il est pris en charge pour les éléments contenteditable dans Mozilla en cours (de Firefox 14) et les navigateurs WebKit / Blink, mais pas IE.

Démo:

document.getElementById("editor").addEventListener("input", function() {
    console.log("input event fired");
}, false);
<div contenteditable="true" id="editor">Please type something in here</div>

Démo: http://jsfiddle.net/ch6yn/2691/

Autres conseils

Voici une version plus efficace qui utilise on pour tous contenteditables. Il est basé au large des réponses top ici.

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

Le projet est ici: https://github.com/balupton/html5edit

Pensez à utiliser MutationObserver . Ces observateurs sont conçus pour réagir aux changements dans les DOM et en remplacement performant pour événements Mutation.

Avantages:

  • Se déclenche lorsque any changement se produit, ce qui est difficile à réaliser en écoutant les événements clés comme suggéré par d'autres réponses. Par exemple, tous ces travaux: faites glisser-déposer, italiques, copier / couper / coller dans le menu contextuel
  • .
  • Conçu avec des performances à l'esprit.
  • Le code simple et direct. Il est beaucoup plus facile à comprendre et le code de débogage qui écoute un événement plutôt que le code qui écoute 10 événements.
  • Google a une excellente qui rend l'utilisation MutationObservers très facile.

Moins:

  • nécessite une version très récente de Firefox (14.0+), Chrome (18+), ou IE (11 +).
  • Nouvelle API pour comprendre
  • Pas beaucoup d'informations disponibles encore sur les meilleures pratiques ou des études de cas

En savoir plus:

non jQuery rapide et sale réponse:

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);
});

Je l'ai modifié lawwantsin « s réponse comme si ce qui fonctionne pour moi. J'utilise l'événement keyup au lieu de keypress qui fonctionne très bien.

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

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

Deux options:

1) Pour les navigateurs modernes (à feuilles persistantes): L'événement « d'entrée » agirait comme un événement « changement » alternative.

https://developer.mozilla.org/en-US / docs / Web / événements / entrée

document.querySelector('div').addEventListener('input', (e) => {
    // Do something with the "change"-like event
});

ou

<div oninput="someFunc(event)"></div>

ou (avec jQuery)

$('div').on('click', function(e) {
    // Do something with the "change"-like event
});

2) Pour tenir compte des navigateurs IE11 et modernes (à feuilles persistantes): Ce montres pour les changements d'éléments et leur contenu à l'intérieur du 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 });

Voici ce qui a fonctionné pour moi:

   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);
            }
   });

Ce fil a été très utile alors que je faisais des recherches sur le sujet.

J'ai modifié une partie du code ici dans un plugin jQuery il est donc sous une forme réutilisable, principalement pour satisfaire mes besoins, mais d'autres peuvent apprécier une interface plus simple pour démarrer en utilisant les balises contenteditable.

https://gist.github.com/3410122

Mise à jour:

En raison de sa popularité croissante du plugin a été adopté par Makesites.org

Le développement se poursuivra d'ici:

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

Voici la solution que je fini par utiliser et fonctionne fabuleusement. J'utilise $ (this) .text () au lieu parce que je suis juste en utilisant un div d'une ligne qui est modifiable contenu. Mais vous pouvez aussi utiliser .html () de cette façon vous n'avez pas à vous soucier de la portée d'une variable globale / non globale et l'avant est réellement attaché à l'éditeur 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!');
    }
});

réponse non JQuery ...

function makeEditable(elem){
    elem.setAttribute('contenteditable', 'true');
    elem.addEventListener('blur', function (evt) {
        elem.removeAttribute('contenteditable');
        elem.removeEventListener('blur', evt.target);
    });
    elem.focus();
}

Pour l'utiliser, appelez le (par exemple) un élément d'en-tête avec id = "myHeader"

makeEditable(document.getElementById('myHeader'))

Cet élément sera désormais modifiable par l'utilisateur jusqu'à ce qu'il perd le focus.

L'événement onchange ne pas se déclenche quand un élément avec l'attribut contentEditable est modifié, une approche suggérée pourrait être d'ajouter un bouton, « Enregistrer » l'édition.

Vérifier ce plugin qui gère le problème de cette façon:

Pour éviter les minuteries et les boutons « sauver », vous pouvez utiliser les feux de wich événement flou lorsque l'élément perd le focus. mais pour être sûr que l'élément a été réellement changé (et pas seulement concentré et défocalisation), son contenu doit être comparé à sa dernière version. ou utiliser l'événement KeyDown pour définir un certain drapeau « sale » à cet égard.

Utilisation DOMCharacterDataModified sous MutationEvents conduira à la même chose. Le délai d'attente est configuré pour empêcher l'envoi des valeurs incorrectes (par exemple dans Chrome j'ai eu quelques problèmes avec la barre d'espace)

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 exemple

J'ai construit un plugin jQuery pour le faire.

(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);

Vous pouvez simplement appeler $('.wysiwyg').wysiwygEvt();

Vous pouvez également supprimer / ajouter des événements si vous souhaitez

Une réponse simple à JQuery, je viens de créer ce code et je pensais que ce sera utile aussi pour les autres

    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
        }           
    });

Cochez cette idée sur. http://pastie.org/1096892

Je pense qu'il est proche. HTML 5 a vraiment besoin d'ajouter l'événement de changement à la spécification. Le seul problème est que la fonction de rappel évalue si (avant == $ (this) .html ()) avant que le contenu est effectivement mis à jour en $ (this) .html (). setTimeout ne fonctionne pas, et il est triste. Faites-moi savoir ce que vous pensez.

Sur la base de la réponse de @ 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>

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top