430

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

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

4

21 回答 21

375

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

2014 年 10 月 29 日更新

从长远来看,HTML5input事件是答案。在撰写本文时,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>

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

于 2009-09-11T14:39:53.277 回答
207

这是一个更有效的版本,可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

于 2011-06-07T09:54:30.617 回答
59

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

优点:

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

缺点:

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

学到更多:

  • 我写了一个小片段来比较使用 MutationObserers 处理各种事件。我使用了 balupton 的代码,因为他的回答获得了最多的支持。
  • Mozilla在 API 上有一个很棒的页面
  • 看看MutationSummary
于 2012-12-26T17:24:42.060 回答
26

非 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);
});
于 2015-10-11T12:10:15.067 回答
22

我已经像这样修改了 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')});
于 2010-09-13T14:06:58.083 回答
17

两种选择:

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 });
于 2018-03-14T20:23:22.317 回答
8

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

于 2018-11-07T10:29:14.890 回答
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);
            }
   });
于 2011-01-28T21:09:04.207 回答
3

在我调查该主题时,此线程非常有帮助。

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

https://gist.github.com/3410122

更新:

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

开发将从这里继续:

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

于 2012-08-21T07:36:32.400 回答
2

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

于 2010-05-09T06:19:14.917 回答
2

这是我最终使用的解决方案,效果非常好。我改用 $(this).text() 是因为我只使用了一个可编辑内容的单行 div。但是您也可以这样使用 .html() ,您不必担心全局/非全局变量的范围,并且之前实际上附加到编辑器 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!');
    }
});
于 2011-05-05T17:22:51.800 回答
2

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

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

于 2016-05-17T09:09:51.107 回答
2

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


于 2019-11-17T17:15:02.213 回答
1

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
        }           
    });
于 2016-03-29T09:44:53.923 回答
1

您需要使用输入事件类型

演示

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

了解更多

于 2021-04-01T01:36:50.490 回答
0

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

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

于 2009-09-07T23:56:10.700 回答
0

在 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 示例

于 2012-02-28T14:33:57.770 回答
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();

如果您愿意,您还可以删除/添加事件

于 2013-06-04T16:22:53.730 回答
0

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

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

技巧:当你编辑完成后,通常会触发模糊事件。

例子

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

于 2021-10-18T07:41:13.230 回答
-1

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

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

于 2010-08-17T03:14:52.677 回答
-2

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

于 2017-08-30T18:25:34.760 回答