2012-01-01 25 views
22

código como:evento onChange con contenteditable

...text <span contenteditable="true" onChange="someFunction()">blah blah</span> text... 

El evento onChange no funciona. (al menos en FireFox)
No quiero usar etiquetas textarea/input, porque debe estar disponible para cambiar solo palabras particulares en el texto, y debe mostrarse en línea (no en bloque).

¿Hay alguna manera de hacerlo?

+1

por qué no utilizar un elemento de 'input' y el estilo de distancia de la frontera/de relleno y crea en' pantalla: inline' o 'display: inline-block' – Chad

Respuesta

6

La función que escribí:
Una llamada de esta función corrige todos los elementos de ContentEditable en la página.

function fix_onChange_editable_elements() 
{ 
    var tags = document.querySelectorAll('[contenteditable=true][onChange]');//(requires FF 3.1+, Safari 3.1+, IE8+) 
    for (var i=tags.length-1; i>=0; i--) if (typeof(tags[i].onblur)!='function') 
    { 
    tags[i].onfocus = function() 
    { 
     this.data_orig=this.innerHTML; 
    }; 
    tags[i].onblur = function() 
    { 
     if (this.innerHTML != this.data_orig) 
     this.onchange(); 
     delete this.data_orig; 
    }; 
    } 
} 
+1

Si necesita saber acerca de los cambios "en vivo", el principio anterior se puede adaptar para trabajar bajo un 'setInterval' (con una configuración de intervalo razonable y un eventual' clearInterval'). –

23

No realmente. Los últimos navegadores WebKit admiten el evento HTML5 input en elementos contenteditable, que es ideal, pero no es compatible con otros navegadores (ACTUALIZACIÓN 31 de diciembre de 2012: Firefox admite esto a partir de la versión 14). De lo contrario, puede cumplir con DOM mutation eventsDOMNodeInserted, DOMNodeRemoved y DOMCharacterDataModified, pero estos tienen dos desventajas: en primer lugar, no son compatibles con IE < 9 o cualquier versión de Opera para elementos contenteditable, y en segundo lugar, una nueva especificación con eventos de reemplazo está en proceso, lo que significa que es probable que sean reemplazados en futuros navegadores.

ejemplo vivo: http://jsfiddle.net/MBags/

O usted podría ir nivel inferior y manejar llave, ratón y eventos del portapapeles (cut y paste), que funciona en todos los navegadores, pero eso significará que tendrá que comprobar si el el contenido editable ha cambiado cada vez que se desencadena un evento de este tipo, que se ralentiza y daña la experiencia del usuario para grandes cantidades de contenido.

+0

onInput event es una solución muy pobre. primer motivo: ocurre cada vez que el usuario cambia incluso una sola letra. Segundo motivo: no funciona incluso en FireFox 8.0 –

+4

@ Dani-Br: ¿Qué? Mi respuesta dice que el evento 'input' solo es compatible con WebKit, por lo tanto, no en Firefox. En segundo lugar, su pregunta no es clara sobre * cuando * necesita detectar cambios en el contenido editable; el evento 'input' es el evento más similar al evento' change' de las entradas de formulario, aunque reconozco que son bastante diferentes. –

+0

Desafortunadamente, el evento _input_ no funciona en elementos _contenteditable_ en IE, ¡ni siquiera en IE10! – AnAurelian

4

Como los elementos sin entrada no tienen eventos tradicionales similares a la entrada, tiene que ordenar algo juntos. Para ello:

var editable = document.querySelectorAll('div[contentEditable]'); 

for (var i=0, len = editable.length; i<len; i++){ 
    editable[i].setAttribute('data-orig',editable[i].innerHTML); 

    editable[i].onblur = function(){ 
     if (this.innerHTML == this.getAttribute('data-orig')) { 
      // no change 
     } 
     else { 
      // change has happened, store new value 
      this.setAttribute('data-orig',this.innerHTML); 
     } 
    }; 
} 

JS Fiddle demo.

Aunque como se señala en Tim Down, esto no debería ser necesario por mucho más tiempo, con la obvia excepción de admitir navegadores más antiguos.

9

Creé 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'); 
        htmlOld = htmlNew; 
       } 
      }) 
     }) 
    } 
})(jQuery); 

Usted puede simplemente llamar $('.wysiwyg').wysiwygEvt();

También puede eliminar/añadir eventos si desea

+0

Dale me gusta a tu código, pero "eso" parece indefinido. – AnthonyVO

+0

gracias, arreglado .. – Blowsie

+1

Espera, todo esto solo funcionará una vez, o todo el evento de tiempo cuando simplemente te desdibujas si haces un solo cambio una vez, ya que 'htmlold' solo se define una vez, y nunca anulado al estado actual! – Val