Answers:
我建议将侦听器附加到由editable元素触发的关键事件上,尽管您需要注意,keydown
并且keypress
在更改内容本身之前会触发事件。这不会涵盖更改内容的所有可能方法:用户还可以从“编辑”或上下文浏览器菜单中使用剪切,复制和粘贴,因此您可能也想处理cut
copy
和paste
事件。另外,用户可以放置文本或其他内容,因此在那里有更多事件(mouseup
例如,)。您可能希望轮询元素的内容作为后备。
2014年10月29日更新
从长远来看,HTML5 input
事件是答案。在撰写本文时,contenteditable
当前Mozilla(来自Firefox 14)和WebKit / Blink浏览器中的元素均支持该功能,但IE不支持。
演示:
document.getElementById("editor").addEventListener("input", function() {
console.log("input event fired");
}, false);
<div contenteditable="true" id="editor">Please type something in here</div>
cut
,copy
以及paste
支持它们的浏览器中的事件(IE 5 +,Firefox 3.0 +,Safari 3 +,Chrome)
input
事件应涵盖所有这些。
这是on
用于所有contenteditables 的更有效的版本。它基于此处的最佳答案。
$('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
document.getElementById('editor_input').innerHTML = 'ssss'
。缺点是它需要IE11
考虑使用MutationObserver。这些观察者旨在对DOM中的更改做出反应,并作为Mutation Events的高性能替代品。
优点:
缺点:
学到更多:
input
事件(contenteditable
在所有支持突变观察者的WebKit和Mozilla浏览器中都支持)并不完全相同,因为DOM突变可以通过脚本以及用户输入发生,但是对于那些浏览器而言,这是一个可行的解决方案。我想这可能比input
比赛对表演的危害更大,但是对此我没有确凿的证据。
input
在以下每种情况下(特别是通过上下文菜单进行拖放,斜体化,复制/剪切/粘贴)都会触发HTML5 事件。我还测试了w / cmd / ctrl + b的粗体,并获得了预期的结果。我还检查并能够验证该input
事件不会在程序更改上触发(这似乎很明显,但可以说与相关的MDN页面上的某些令人困惑的语言相反;请参阅此处的底部以了解我的意思:开发人员.mozilla.org / zh-CN / docs / Web / Events / input)
非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);
});
两种选择:
1)对于现代(常绿)浏览器: “输入”事件将作为替代的“更改”事件。
https://developer.mozilla.org/zh-CN/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/zh-CN/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 />
这对我有用:
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插件,因此它是可重用的形式,主要是为了满足我的需求,但其他人可能会喜欢使用ContentEditable标签的更简单的界面来快速入门。
https://gist.github.com/3410122
由于其日益流行,该插件已被Makesites.org采用
开发将从此处继续:
这是我最终使用并出色工作的解决方案。我改用$(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!');
}
});
在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
}
});
$("div [contenteditable=true]")
将直接或间接选择可编辑的div的所有子级。
非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'))
用户现在可以编辑该元素,直到失去焦点。
当更改带有contentEditable属性的元素时,不会触发onchange事件,建议的方法是添加一个按钮,以“保存”版本。
检查以这种方式处理问题的此插件:
在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());
})
DOMCharacterDataModified
用户修改现有文本(例如应用粗体或斜体)时不会触发。 DOMSubtreeModified
在这种情况下更合适。另外,人们应该记住,旧版浏览器不支持这些事件。
我建立了一个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();
您还可以根据需要删除/添加事件
innerHTML
昂贵)。我建议使用input
存在的事件,并回退到类似事件,但要进行某种程度的反跳。
在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
}
}
请遵循以下简单的解决方案
在.ts中:
getContent(innerText){
this.content = innerText;
}
在.html中:
<div (blur)="getContent($event.target.innerHTML)" contenteditable [innerHTML]="content"></div>
看看这个想法。 http://pastie.org/1096892
我想快了。HTML 5确实需要将change事件添加到规范中。唯一的问题是,在实际在$(this).html()中更新内容之前,回调函数会评估(== $(this).html()之前)是否。setTimeout不起作用,这很可悲。让我知道你的想法。
基于@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>
document.getElementById("editor").oninput = function() { ...}
。