Réponses:
Je vous suggère d' attache des auditeurs à des événements clés tirés par l'élément modifiable, mais vous devez être conscient que keydown
et keypress
événements sont déclenchés avant que le contenu lui - même est changé. Cela ne couvrira pas tous les moyens possibles de modifier le contenu: l'utilisateur peut également utiliser couper, copier et coller à partir des menus du navigateur d'édition ou de contexte, vous pouvez donc également gérer les événements cut
copy
et paste
. De plus, l'utilisateur peut supprimer du texte ou d'autres contenus, il y a donc plus d'événements ( mouseup
par exemple). Vous souhaiterez peut-être interroger le contenu de l'élément comme solution de rechange.
MISE À JOUR 29 octobre 2014
L' événement HTML5input
est la réponse à long terme. Au moment de la rédaction, il est pris en charge pour les contenteditable
éléments des navigateurs Mozilla actuels (de Firefox 14) et 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>
cut
, copy
et les paste
événements dans les navigateurs qui les soutiennent (IE 5+, Firefox 3.0+, Safari 3+, Chrome)
input
événement HTML5 .
Voici une version plus efficace qui utilise on
pour tous les contenus modifiables. Il est basé sur les meilleures réponses 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
document.getElementById('editor_input').innerHTML = 'ssss'
. L'inconvénient est qu'il nécessite IE11
Pensez à utiliser MutationObserver . Ces observateurs sont conçus pour réagir aux changements dans les DOM, et en remplacement performant des événements de mutation .
Avantages:
Les inconvénients:
Apprendre encore plus:
input
événement HTML5 (qui est pris contenteditable
en charge dans tous les navigateurs WebKit et Mozilla qui prennent en charge les observateurs de mutation), car la mutation DOM peut se produire via un script ainsi que l'entrée utilisateur, mais c'est une solution viable pour ces navigateurs. J'imagine que cela pourrait nuire à la performance plus que l' input
événement aussi, mais je n'ai aucune preuve tangible pour cela.
input
événement HTML5 se déclenche dans chacune de ces situations (en particulier glisser-déposer, italique, copier / couper / coller via le menu contextuel). J'ai également testé le bolding w / cmd / ctrl + b et obtenu les résultats attendus. J'ai également vérifié et j'ai pu vérifier que l' input
événement ne se déclenche pas sur les changements de programmation (ce qui semble évident, mais est sans doute contraire à un langage déroutant sur la page MDN pertinente; voir le bas de la page ici pour voir ce que je veux dire: développeur .mozilla.org / en-US / docs / Web / Events / input )
J'ai modifié la réponse de lawwantsin comme ça et cela 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')});
réponse non jQuery rapide et sale :
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);
});
Deux options:
1) Pour les navigateurs modernes (à feuilles persistantes): L'événement "input" agirait comme un événement "change" alternatif.
https://developer.mozilla.org/en-US/docs/Web/Events/input
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 prendre en compte IE11 et les navigateurs modernes (à feuilles persistantes): Cela surveille les changements d'éléments et leur contenu à l'intérieur de la 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 />
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 pendant que j'enquêtais sur le sujet.
J'ai modifié une partie du code disponible ici dans un plugin jQuery afin qu'il soit sous une forme réutilisable, principalement pour répondre à mes besoins, mais d'autres peuvent apprécier une interface plus simple pour démarrer en utilisant des balises modifiables.
https://gist.github.com/3410122
En raison de sa popularité croissante, le plugin a été adopté par Makesites.org
Le développement se poursuivra à partir d'ici:
Voici la solution que j'ai finalement utilisée et qui fonctionne à merveille. J'utilise $ (this) .text () à la place parce que j'utilise juste un div d'une ligne dont le contenu est modifiable. Mais vous pouvez également 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 en fait 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!');
}
});
Pour éviter les minuteries et les boutons "enregistrer", vous pouvez utiliser un événement flou qui se déclenche lorsque l'élément perd le focus. mais pour être sûr que l'élément a bien été modifié (pas seulement focalisé et défocalisé), son contenu doit être comparé à sa dernière version. ou utilisez l'événement keydown pour définir un indicateur "sale" sur cet élément.
Une réponse simple dans JQuery, je viens de créer ce code et j'ai pensé qu'il serait utile pour les autres aussi
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]")
sélectionnera tous les enfants d'un div, directement ou indirectement, qui sont modifiables.
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 (disons) 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 se déclenche pas lorsqu'un élément avec l'attribut contentEditable est modifié, une approche suggérée pourrait être d'ajouter un bouton, de "sauvegarder" l'édition.
Vérifiez ce plugin qui gère le problème de cette manière:
L'utilisation de DOMCharacterDataModified sous MutationEvents entraînera la même chose. Le délai est configuré pour empêcher l'envoi de valeurs incorrectes (par exemple, dans Chrome, j'ai eu quelques problèmes avec la touche 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());
})
DOMCharacterDataModified
ne se déclenche pas lorsque l'utilisateur modifie du texte existant, par exemple en appliquant du gras ou de l'italique. DOMSubtreeModified
est plus approprié dans ce cas. De plus, les utilisateurs doivent se rappeler que les anciens navigateurs ne prennent pas en charge ces événements.
J'ai construit un plugin jQuery pour ce 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 le souhaitez
innerHTML
est cher). Je recommanderais d'utiliser l' input
événement où il existe et de revenir à quelque chose comme ça, mais avec une sorte de rebond.
Dans Angular 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
}
}
Veuillez suivre la solution simple suivante
En .ts:
getContent(innerText){
this.content = innerText;
}
en .html:
<div (blur)="getContent($event.target.innerHTML)" contenteditable [innerHTML]="content"></div>
Découvrez cette idée. http://pastie.org/1096892
Je pense que c'est proche. HTML 5 doit vraiment ajouter l'événement change à la spécification. Le seul problème est que la fonction de rappel évalue si (avant == $ (this) .html ()) avant que le contenu ne soit réellement mis à jour dans $ (this) .html (). setTimeout ne fonctionne pas, et c'est triste. Laissez-moi savoir ce que vous pensez.
D'après 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>
document.getElementById("editor").oninput = function() { ...}
.