可以理解的变化事件

我想在用户使用contenteditable属性编辑div的内容时运行一个函数。 什么是onchange事件的等价物?

我正在使用jQuery,所以任何使用jQuery的解决scheme是首选。 谢谢!

我build议将侦听器附加到由editable元素触发的关键事件,但是您需要知道在更改内容本身之前触发keydownkeypress事件。 这不会涵盖更改内容的所有可能方法:用户也可以使用剪辑,复制和粘贴从编辑或上下文浏览器菜单,所以您可能也想要处理cut copypaste事件。 而且,用户可以放置文本或其他内容,所以在那里有更多的事件(例如mouseup )。 您可能需要轮询元素的内容作为后备。

更新2014年10月29日

HTML5 input事件是长期的答案。 在撰写本文时,它支持当前Mozilla(来自Firefox 14)和WebKit / Blink浏览器(但不包括IE)中的可contenteditable元素。

演示: http : //jsfiddle.net/ch6yn/

这是一个更有效的版本,用于所有contenteditables。 这是基于这里的最佳答案。

在使用jQuery的CoffeeScript中:

 $('body') .on 'focus', '[contenteditable]', -> $this = $(this) $this.data 'before', $this.html() return $this .on 'blur keyup paste input', '[contenteditable]', -> $this = $(this) if $this.data('before') isnt $this.html() $this.data 'before', $this.html() $this.trigger('change') return $this 

在使用jQuery的JavaScript中:

 $('body').on('focus', '[contenteditable]', function() { var $this = $(this); $this.data('before', $this.html()); return $this; }).on('blur keyup paste input', '[contenteditable]', function() { var $this = $(this); if ($this.data('before') !== $this.html()) { $this.data('before', $this.html()); $this.trigger('change'); } return $this; }); 

该项目在这里: https : //github.com/balupton/html5edit

考虑使用MutationObserver 。 这些观察者被devise为对DOM中的变化作出反应,并作为突变事件的高性能替代。

优点:

  • 发生任何变化时发生,这是通过听其他答案build议的关键事件难以实现的。 例如,所有这些工作都很好:通过上下文菜单拖放,斜体,复制/剪切/粘贴。
  • 考虑到性能而devise。
  • 简单,直接的代码。 理解和debugging侦听一个事件的代码比监听10个事件的代码要容易得多。
  • Google有一个很好的突变概要库 ,使得使用MutationObservers非常容易。

缺点:

  • 需要最新版本的Firefox(14.0+),Chrome(18+)或IE(11+)。
  • 新API了解
  • 关于最佳做法或案例研究的信息还不多

学到更多:

  • 我写了一个小片段来比较使用MutationObserer来处理各种事件。 我使用了balupton的代码,因为他的答案是最有价值的。
  • Mozilla在API上有非常好的一页
  • 看看MutationSummary库

我已经修改了lawwantsin的答案,所以这对我很有用。 我使用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')}); 

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

以下是对我有用的东西:

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

当我调查这个主题的时候,这个主题非常有帮助。

我已经将一些可用的代码修改为一个jQuery插件,所以它是一个可重用的forms,主要是为了满足我的需求,但其他人可能会喜欢更简单的接口来使用contenteditable标签来启动。

https://gist.github.com/3410122

更新:

由于它越来越受欢迎,该插件已被Makesites.org采用

发展将从此继续下去:

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

这是我最终使用和解决scheme的解决scheme。 我使用$(this).text()来代替,因为我只是使用一个内容可编辑的单行div。 但是,您也可以使用.html()这种方式,您不必担心全局/非全局variables的范围,并且before实际上是连接到编辑器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!'); } }); 

当具有contentEditable属性的元素发生更改时,onchange事件不会触发,build议的方法可能是添加一个button来“保存”版本。

检查以这种方式处理问题的插件:

  • 创build一个快速和肮脏的jQuery contentEditable插件

为了避免定时器和“保存”button,当元素失去焦点时,可以使用模糊事件。 但要确保元素实际上已经改变(不仅仅是聚焦和散焦),其内容应该与其最后的版本进行比较。 或者使用keydown事件在这个元素上设置一些“脏”标志。

在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的例子

我build立了一个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();

您也可以根据需要删除/添加事件

在JQuery中一个简单的答案,我刚刚创build了这个代码,并认为这对其他人也有帮助

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

检查这个想法。 http://pastie.org/1096892

我觉得这很接近。 HTML 5确实需要将更改事件添加到规范中。 唯一的问题是,callback函数在$(this).html()中实际更新内容之前评估if(before == $(this).html())。 setTimeout不起作用,而且很伤心。 让我知道你的想法。

非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')) 

该元素现在可以由用户编辑,直到失去焦点。

基于@ 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>