可编辑元素的onChange事件

50

代码示例:

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

onChange事件在FireFox中不起作用。我不想使用文本区域/输入标签,因为必须仅可更改文本中的特定单词,并且必须以内联方式显示(而非块级元素)。

有没有什么办法可以做到这一点?


1
为什么不使用 input 元素并去掉边框/填充样式,将其设为 display:inlinedisplay:inline-block - Chad
4个回答

35
实际上,最新的WebKit浏览器支持contenteditable元素上的HTML5 input事件,这非常理想,但在其他浏览器中不受支持(更新于2012年12月31日:Firefox从版本14开始支持此功能)。否则,您可能需要使用DOM突变事件DOMNodeInsertedDOMNodeRemovedDOMCharacterDataModified,但这有两个缺点:首先,在IE&lt; 9或任何版本的Opera中不支持这些功能用于contenteditable元素,其次,正在制定替代事件的新规范,这意味着它们很可能会在未来的浏览器中被替换。

实时示例:http://jsfiddle.net/MBags/

或者,您可以降低级别并处理键、鼠标和剪贴板事件(cutpaste),这将在所有主要浏览器中工作,但这意味着每次此类事件发生时您都需要检查可编辑内容是否已更改,这将对大块内容造成滞后并损害用户体验。


1
onInput事件是非常不好的解决方案。第一个原因-每次用户更改一个字母时都会触发。第二个原因-它甚至在FireFox 8.0中也不能正常工作。 - Dani-Br
5
@Dani-Br:什么?我的回答说input事件仅在WebKit中受支持,因此不适用于Firefox。其次,您的问题并没有清楚表明何时需要检测可编辑内容的更改;input事件是类似于表单输入的change事件,尽管它们有很大的不同。 - Tim Down
很不幸,即使在IE10中,_contenteditable_元素上的_input_事件也无法工作! - TechAurelian

15

我编写了一个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');
                    htmlOld = htmlNew;
                }
            })
        })
    }
})(jQuery);

你可以简单地调用$('.wysiwyg').wysiwygEvt();

如果需要,你也可以删除/添加事件。


10
我编写的函数:
调用此函数可修复页面中所有ContentEditable元素。
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
如果您需要了解“实时”更改,上述原则可以适应于在setInterval下工作(具有合理的间隔设置和最终的clearInterval)。 - Oliver Moran

9
由于非输入元素没有传统的类似输入的事件,您需要自己将它们组合在一起。为此:
因为非输入元素不具备传统的输入事件,你需要自行组合。为此:
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演示

尽管如Tim Down所指出的那样,这不再是必需的,除了支持旧版浏览器外。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接