可满足的更改事件

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

我使用jQuery,所以使用jQuery的任何解决方案都是首选。谢谢!

331643 次浏览

onchange事件不会在具有contentEditable属性的元素被更改时触发,建议的方法是添加一个按钮到“保存”的版本中。

检查这个插件,它以这种方式处理问题:

2022年更新

正如评论中所指出的,这并没有回答所提出的问题,即想要等价于change事件而不是input事件。不过,我还是把它留在这里吧。

原来的答案

我建议将监听器附加到由可编辑元素触发的关键事件,尽管你需要知道keydownkeypress事件是在内容本身被更改之前触发的。这不会涵盖所有可能的改变内容的方法:用户也可以使用Edit或上下文浏览器菜单中的剪切、复制和粘贴,所以你可能也想处理cut copypaste事件。此外,用户可以删除文本或其他内容,因此那里有更多的事件(例如mouseup)。您可能希望轮询元素的内容作为备选方案。

2014年10月29日更新

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

演示:

document.getElementById("editor").addEventListener("input", function() {
console.log("input event fired");
}, false);
<div contenteditable="true" id="editor">Please type something in here</div>

Demo: http://jsfiddle.net/ch6yn/2691/

为了避免计时器和“保存”按钮,你可以使用blur事件,当元素失去焦点时触发。但是为了确保元素确实被改变了(不仅仅是聚焦和散焦),它的内容应该与它的上一个版本进行比较。或者使用keydown事件在这个元素上设置一些“脏”标志。

看看这个想法。 http://pastie.org/1096892 < / p >

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

我修改了律法,希望罪恶的答案是这样的,这对我有用。我使用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')});

以下是对我有效的方法:

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

下面是我最终使用的解决方案,效果非常好。我使用$(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!');
}
});

下面是一个更有效的版本,它对所有可内容使用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

使用在MutationEvents下修改domcharacterdatmodified将导致相同的结果。超时设置是为了防止发送错误的值(例如,在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示例 .

这个帖子在我调查这个主题的时候非常有帮助。

我把这里的一些代码修改成一个jQuery插件,这样它就可以以一种可重用的形式使用,主要是为了满足我的需求,但其他人可能更喜欢一个简单的界面来使用可满足的标记。

https://gist.github.com/3410122

更新:

由于其日益流行的插件已被Makesites.org采用

发展将从这里开始:

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

考虑使用MutationObserver。这些观察器被设计用来对DOM中的变化做出反应,并作为突变事件的性能替代品。

优点:

  • 任何发生变化时触发,这很难通过侦听其他答案所建议的关键事件来实现。例如,所有这些工作都很好:拖动&删除,斜体,复制/剪切/粘贴上下文菜单。
  • 设计时考虑到性能。
  • 简单、直接的代码。比起监听10个事件的代码,理解和调试监听一个事件的代码要容易得多。
  • 谷歌有一个优秀的突变摘要库,这使得使用mutationobserver非常容易。

缺点:

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

了解更多:

  • 我写了一些片段来比较使用mutationobserver处理各种事件。我使用了balupton的代码,因为他的回答有最多的赞。
  • Mozilla有一个关于API的优秀页面
  • 看一下MutationSummary

我构建了一个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快速和回答:

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

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

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

两个选择:

1)对于现代(常绿)浏览器: "input"事件将作为"change"事件的替代

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

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

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




你需要使用输入事件类型

演示

超文本标记语言

<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

对于我来说,我想检查输入是否有效。

如果有效,则更新,否则显示错误消息并保持值与以前相同。

技能:当你编辑done时,通常会触发模糊事件。

例子

<span contenteditable="true">try input somethings.</span>
<script>
const elem = document.querySelector(`span`)
let oldValue = elem.innerText
elem.onkeydown = (keyboardEvent) => {
if (keyboardEvent.key === "Enter") {
elem.blur() // set focusout
}
}
elem.onblur = (e) => {
const curValue = elem.innerText
if (curValue === oldValue) {
return
}
if (curValue.length <= 50) { // 👈 Input your conditions.
// 👇 fail
elem.innerText = oldValue
      

// (Optional) Add error message
elem.insertAdjacentHTML("beforeend", `<span style="margin-left:5px;color:red">error length=${curValue.length}. Must greater than 50. undo to the previous value.</span>`)
const errMsg = elem.querySelector(`span`)
setTimeout(() => errMsg.remove(), 3500) // wait 3.5 second, and then remove it.
return
}
// 👇 OK, update
oldValue = curValue
}
</script>