令人满意的变革事件

时间:2009-09-07 23:15:12

标签: javascript jquery html5 contenteditable

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

我正在使用jQuery,因此任何使用jQuery的解决方案都是首选。谢谢!

20 个答案:

答案 0 :(得分:261)

我建议将侦听器附加到可编辑元素触发的关键事件,但您需要知道在更改内容本身之前会触发keydownkeypress个事件。这不会涵盖更改内容的所有可能方法:用户还可以使用编辑或上下文浏览器菜单中的剪切,复制和粘贴,因此您可能希望处理cut copy和{ {1}}事件也是如此。此外,用户可以删除文本或其他内容,因此其中有更多事件(例如paste)。您可能希望将元素的内容轮询为后备。

2014年10月29日更新

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

<强>演示:

contenteditable
document.getElementById("editor").addEventListener("input", function() {
    console.log("input event fired");
}, false);

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

答案 1 :(得分:176)

这是一个更有效的版本,它使用on来表示所有可信任的版本。它基于这里的最佳答案。

$('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');
    }
});

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

答案 2 :(得分:49)

考虑使用MutationObserver。这些观察者旨在对DOM的变化作出反应,并作为Mutation Events的高效替代者。

优点:

  • 发生任何更改时触发,这很难通过听取其他答案建议的关键事件来实现。例如,所有这些都运作良好:拖动和放大通过上下文菜单删除,斜体,复制/剪切/粘贴。
  • 考虑到性能而设计。
  • 简单明了的代码。理解和调试监听一个事件的代码比听取10个事件的代码要容易得多。
  • Google有一个很好的mutation summary library,这使得使用MutationObservers非常容易。

缺点:

  • 需要最新版本的Firefox(14.0 +),Chrome(18+)或IE(11 +)。
  • 要理解的新API
  • 目前尚未提供有关最佳做法或案例研究的大量信息

了解详情:

  • 我写了一点snippet来比较使用MutationObserers来处理各种事件。我使用了balupton的代码,因为他的answer有最多的赞成。
  • Mozilla在API上有一个很好的页面
  • 查看MutationSummary

答案 3 :(得分:20)

我修改了lawwantsin的回答,这对我有用。我使用的是keyup事件,而不是keypress,效果很好。

 
$('#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')});

答案 4 :(得分:20)

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

答案 5 :(得分:4)

两个选项:

1)对于现代(常青树)浏览器: “输入”事件将作为替代“变更”事件。

https://developer.mozilla.org/en-US/docs/Web/Events/input

document.querySelector('div').addEventListener('input', (e) => {
    // Do something with the "change"-like event
});

<div oninput="someFunc(event)"></div>

或(使用jQuery)

$('div').on('click', function(e) {
    // Do something with the "change"-like event
});

2)考虑IE11和现代(常青树)浏览器: 这会监视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 });

答案 6 :(得分:3)

这对我有用:

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

答案 7 :(得分:3)

在我调查这个主题时,这个帖子非常有用。

我已将这里提供的一些代码修改为jQuery插件,因此它是一个可重复使用的形式,主要是为了满足我的需求,但其他人可能会喜欢使用contenteditable标签快速启动的简单界面。

https://gist.github.com/3410122

更新

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

采用

发展将从这里继续:

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

答案 8 :(得分:2)

这是我最终使用的解决方案,并且工作非常棒。我使用$(this).text()代替,因为我只使用内容可编辑的一行div。但是你也可以使用.html()这种方式你不必担心全局/非全局变量的范围,而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!');
    }
});

答案 9 :(得分:2)

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 />

答案 10 :(得分:0)

您需要使用输入事件类型

演示

HTML

<div id="editor" contenteditable="true" >Some text here</div>

JS

const input = document.getElementById('editor');


input.addEventListener('input', updateValue);

function updateValue(e) {
  console.log(e.target);
}

know more

答案 11 :(得分:0)

在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 
 }
}


答案 12 :(得分:0)

非JQuery回答......

eval

要使用它,请调用(比方说)带有id =“myHeader”

的标题元素
function makeEditable(elem){
    elem.setAttribute('contenteditable', 'true');
    elem.addEventListener('blur', function (evt) {
        elem.removeAttribute('contenteditable');
        elem.removeEventListener('blur', evt.target);
    });
    elem.focus();
}

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

答案 13 :(得分:0)

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

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

答案 14 :(得分:0)

我构建了一个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();

即可

如果您愿意,也可以删除/添加活动

答案 15 :(得分:0)

当具有contentEditable属性的元素发生更改时,onchange事件不会触发,建议的方法可能是添加按钮,“save”该版本。

选中以这种方式处理问题的插件:

答案 16 :(得分:0)

使用DOMCharacterDataModified under MutationEvents会导致相同的情况。设置超时是为了防止发送错误的值(例如在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 example

答案 17 :(得分:0)

要避免使用计时器和“保存”按钮,您可能会在元素失去焦点时使用模糊事件。但为了确保元素实际上已被更改(不仅仅是聚焦和散焦),应将其内容与其上一版本进行比较。或使用keydown事件在此元素上设置一些“脏”标志。

答案 18 :(得分:-1)

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

我认为它很接近。 HTML 5确实需要将更改事件添加到规范中。唯一的问题是回调函数在$(this).html()中实际更新内容之前评估if(= = $(this).html()之前)。 setTimeout不起作用,很难过。让我知道你的想法。

答案 19 :(得分:-2)

根据@ balupton的回答:

&#13;
&#13;
$(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')
	}
})
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
&#13;
&#13;
&#13;