javascript - contenteditable jquery change
eventos de cambio contenteditable (18)
Quiero ejecutar una función cuando un usuario edita el contenido de un div
con un atributo contenteditable
. ¿Cuál es el equivalente de un evento onchange
?
Estoy usando jQuery, por lo que se prefiere cualquier solución que use jQuery. ¡Gracias!
Aquí está la solución que terminé usando y funciona fabulosamente. Utilizo $ (this) .text () en su lugar porque solo estoy usando un div de una línea que es editable por contenido. Pero también puede usar .html () de esta manera, no tiene que preocuparse por el alcance de una variable global / no global y el anterior se adjunta al div editor.
$(''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!'');
}
});
Aquí hay una versión más eficiente que se usa on
todos los contenidos editables. Se basa en las mejores respuestas aquí.
$(''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'');
}
});
El proyecto está aquí: https://github.com/balupton/html5edit
Basado en la respuesta 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>
Considere el uso de MutationObserver . Estos observadores están diseñados para reaccionar a los cambios en el DOM y como un reemplazo eficaz de los eventos de mutación .
Pros:
- Se activa cuando se produce cualquier cambio, lo que es difícil de lograr al escuchar los eventos clave como lo sugieren otras respuestas. Por ejemplo, todos estos funcionan bien: arrastrar y soltar, poner cursiva, copiar / cortar / pegar en el menú contextual.
- Diseñado pensando en el rendimiento.
- Código simple y directo. Es mucho más fácil de entender y depurar el código que escucha un evento en lugar de un código que escucha 10 eventos.
- Google tiene una excelente biblioteca de resumen de mutaciones que facilita el uso de MutationObservers.
Contras:
- Requiere una versión muy reciente de Firefox (14.0+), Chrome (18+) o IE (11+).
- Nueva API para entender
- No hay mucha información disponible todavía sobre las mejores prácticas o estudios de caso
Aprende más:
- Escribí un pequeño here para comparar el uso de MutationObserers con el manejo de una variedad de eventos. Usé el código de balupton ya que su answer tiene el mayor número de votos.
- Mozilla tiene una excelente página en la API
- Echa un vistazo a la biblioteca de resumen de mutaciones.
Construí un plugin de jQuery para hacer esto.
(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);
Simplemente puede llamar a $(''.wysiwyg'').wysiwygEvt();
También puede eliminar / agregar eventos si lo desea
Echa un vistazo a esta idea. http://pastie.org/1096892
Creo que está cerca. HTML 5 realmente necesita agregar el evento de cambio a la especificación. El único problema es que la función de devolución de llamada evalúa if (antes == $ (this) .html ()) antes de que el contenido se actualice en $ (this) .html (). setTimeout no funciona, y es triste. Déjame saber lo que piensas.
El evento onchange no se activa cuando se cambia un elemento con el atributo contentEditable, un enfoque sugerido podría ser agregar un botón para "guardar" la edición.
Marque este plugin que maneja el problema de esa manera:
Este hilo fue muy útil mientras estaba investigando el tema.
He modificado parte del código disponible aquí en un complemento de jQuery, por lo que se encuentra en una forma reutilizable, principalmente para satisfacer mis necesidades, pero otros pueden apreciar una interfaz más sencilla para comenzar a utilizar etiquetas personalizables.
https://gist.github.com/3410122
Actualizar:
Debido a su creciente popularidad, el complemento ha sido adoptado por Makesites.org
El desarrollo continuará desde aquí:
Esto es lo que funcionó para mí:
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);
}
});
He modificado la respuesta de la ley como tal y esto funciona para mí. Uso el evento keyup en lugar de la pulsación de tecla que funciona muy 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'')});
Para evitar los temporizadores y los botones de "guardar", puede usar un evento de desenfoque que se dispara cuando el elemento pierde el foco. pero para estar seguro de que el elemento realmente fue cambiado (no solo enfocado y desenfocado), su contenido debe compararse con su última versión. o use el evento keydown para establecer algún indicador "sucio" en este elemento.
Respuesta no jQuery rápida y sucia :
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);
});
Respuesta no jQuery ...
function makeEditable(elem){
elem.setAttribute(''contenteditable'', ''true'');
elem.addEventListener(''blur'', function (evt) {
elem.removeAttribute(''contenteditable'');
elem.removeEventListener(''blur'', evt.target);
});
elem.focus();
}
Para usarlo, llame a (diga) un elemento de encabezado con id = "myHeader"
makeEditable(document.getElementById(''myHeader''))
Ese elemento ahora será editable por el usuario hasta que pierda el foco.
Una respuesta simple en JQuery, acabo de crear este código y pensé que también será útil para otros.
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
}
});
Usar DOMCharacterDataModified en MutationEvents conducirá a lo mismo. El tiempo de espera se configura para evitar el envío de valores incorrectos (por ejemplo, en Chrome tuve algunos problemas con la tecla de espacio)
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());
})
Yo sugeriría adjuntar escuchas a eventos clave activados por el elemento editable, aunque debe tener en cuenta que los eventos keydown
y keypress
keydown
que se keydown
el contenido. Esto no cubrirá todos los medios posibles para cambiar el contenido: el usuario también puede usar cortar, copiar y pegar desde los menús del navegador de Edición o del contexto, por lo que es posible que también desee controlar los eventos de copy
y paste
. Además, el usuario puede colocar texto u otro contenido, por lo que hay más eventos allí ( mouseup
, por ejemplo). Es posible que desee sondear los contenidos del elemento como una alternativa.
ACTUALIZACIÓN 29 de octubre de 2014
El evento de input
HTML5 es la respuesta a largo plazo. Al momento de escribir, se admite para elementos contenteditable
en los navegadores Mozilla actuales (de Firefox 14) y WebKit / Blink, pero no en IE.
Manifestación:
document.getElementById("editor").addEventListener("input", function() {
console.log("input event fired");
}, false);
<div contenteditable="true" id="editor">Please type something in here</div>
Demostración: http://jsfiddle.net/ch6yn/2691/
Dos opciones:
1) Para los navegadores modernos (de hoja perenne): el evento "input" actuaría como un evento alternativo de "cambio".
developer.mozilla.org/en-US/docs/Web/Events/input
document.querySelector(''div'').addEventListener(''input'', (e) => {
// Do something with the "change"-like event
});
o
<div oninput="someFunc(event)"></div>
o (con jQuery)
$(''div'').on(''click'', function(e) {
// Do something with the "change"-like event
});
2) Para tener en cuenta los navegadores IE11 y modernos (de hoja perenne): esto vigila los cambios de elementos y su contenido dentro de la div.
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 />