contenteditable 변경 이벤트


359

사용자가 divwith contenteditable속성 의 내용을 편집 할 때 함수를 실행하고 싶습니다 . onchange이벤트 와 동등한 것은 무엇입니까 ?

jQuery를 사용하고 있으므로 jQuery를 사용하는 솔루션이 선호됩니다. 감사!


나는 보통 이것을한다 : document.getElementById("editor").oninput = function() { ...}.
Basj

답변:


311

키 이벤트는 편집 가능한 요소에 의해 해고에 당신이 알고 있어야하지만 나는, 부착 청취자를 건의 할 것입니다 keydownkeypress콘텐츠 자체가 변경되기 전에 이벤트가 발사된다. 여기에는 컨텐츠를 변경하는 가능한 모든 방법이 포함되지 않습니다. 사용자는 편집 또는 상황에 맞는 브라우저 메뉴에서 잘라 내기, 복사 및 붙여 넣기를 사용할 수도 있으므로 cut copypaste이벤트도 처리 할 수 있습니다. 또한 사용자는 텍스트 나 다른 컨텐츠를 삭제할 수 있으므로 더 많은 이벤트가 있습니다 ( 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>

데모 : http://jsfiddle.net/ch6yn/2691/


11
나는 또한,이 브라우저의 편집 메뉴 또는 인하 상황에 맞는 메뉴를 사용하여 편집 가능한 요소를 변경할 수 있다는 추가 복사하거나 처리 할 필요가 있습니다, 그래서 내용을 붙여 넣어야합니다 cut, copy그리고 paste브라우저에서 이벤트를 지원하는 (IE 5+, 파이어 폭스 3.0 이상, Safari 3 이상, Chrome)
Tim Down

4
키업을 사용할 수 있으며 타이밍 문제가 없습니다.
Blowsie

2
@Blowsie : 그렇습니다. 그러나 이벤트가 발생하기 전에 자동 반복 키 누르기에서 발생하는 많은 변경 사항이 발생할 수 있습니다. 이 답변에서 고려하지 않은 편집 가능한 텍스트를 변경하는 다른 방법 (예 : 편집 및 상황에 맞는 메뉴를 통한 끌어서 놓기 및 편집)도 있습니다. 장기적으로 이것은 HTML5 input이벤트에 의해 다루어 져야합니다 .
Tim Down

1
디 바운스로 키업을하고 있습니다.
Aen Tan

1
@AndroidDev Chrome을 테스트하고 입력 이벤트도 복사 붙여 넣기시 시작되고 사양에 따라 필요에 따라 잘라집니다. w3c.github.io/uievents/#events-inputevents
fishbone

188

다음은 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


커피 스크립트와 자바 스크립트 모두를위한 감사는, 나를 위해 완벽 근무
jwilcox09

7
contenteditable이 흐리게 표시 될 때까지이 코드에 걸리지 않는 일부 변경 사항이 있습니다. 예 : 드래그 앤 드롭, 상황에 맞는 메뉴에서 잘라 내기 및 브라우저 창에서 붙여 넣기 이 코드를 사용하여 여기에서 상호 작용할 수있는 예제 페이지를 설정했습니다 .
jrullmann

드래그 &는 이미지로드 말을 듣지 않기 때문에 이미지를 삭제가 (내 경우에는 크기 조정 작업을 처리 할 수있는 문제가 있었다) 때 @jrullmann 그래, 난이 코드에 문제가 있었다
세바스티앙 Lorber을

@jrullmann 아주 좋은, 이것은 자바 스크립트로 값을 변경하더라도 콘솔에서 시도하십시오 : document.getElementById('editor_input').innerHTML = 'ssss'. 단점은 IE11이 필요하다는 것입니다

1
@NadavB 그것은 "if ($ this.data ( 'before')! == $ this.html ()) {"에 대한
것이므로

52

MutationObserver 사용을 고려하십시오 . 이 옵저버는 DOM의 변화에 ​​반응하고 Mutation Events 의 성능을 대체하기 위해 설계되었습니다 .

장점 :

  • 화재 어떤 어려운 변화가 발생는 다른 답변에 의해 제안 키 이벤트를 듣고에 의해 달성했다. 예를 들어, 상황에 맞는 메뉴를 통해 끌어서 놓기, 기울임 꼴, 복사 / 잘라 내기 / 붙여 넣기 등이 모두 잘 작동합니다.
  • 성능을 염두에두고 설계되었습니다.
  • 간단하고 간단한 코드. 10 개의 이벤트를 수신하는 코드가 아닌 하나의 이벤트를 수신하는 코드를 이해하고 디버그하는 것이 훨씬 쉽습니다.
  • Google에는 MutationObservers를 매우 쉽게 사용할 수 있는 뛰어난 돌연변이 요약 라이브러리 가 있습니다.

단점 :

  • 최신 버전의 Firefox (14.0+), Chrome (18+) 또는 IE (11+)가 필요합니다.
  • 이해할 새로운 API
  • 모범 사례 또는 사례 연구에 대한 정보는 많지 않습니다.

더 알아보기:

  • MutationObserers를 사용하여 다양한 이벤트를 처리하는 것과 비교할 약간의 스 니펫 을 작성했습니다 . 그의 대답 에 가장 찬란한 의견이 있으므로 balupton의 코드를 사용했습니다 .
  • Mozilla 는 API에 대한 훌륭한 페이지를 가지고 있습니다
  • MutationSummary 라이브러리를 살펴보십시오

DOM 돌연변이는 스크립트뿐만 아니라 사용자 입력을 통해 발생할 수 있기 때문에 HTML5 input이벤트 ( contenteditable돌연변이 관찰자를 지원하는 모든 WebKit 및 Mozilla 브라우저에서 지원됨) 와 완전히 동일 하지는 않지만 해당 브라우저에 적합한 솔루션입니다. input이벤트 보다 성능이 떨어질 수 있다고 생각 하지만 이에 대한 확실한 증거는 없습니다.
Tim Down

2
+1이지만 돌연변이 이벤트가 줄 바꿈의 효과를 컨텐츠 편집 가능으로보고하지 않는다는 것을 알고 계셨습니까? 스 니펫에서 Enter를 누르십시오.
citykid

4
@citykid : 스 니펫이 문자 데이터의 변경 사항 만보고 있기 때문입니다. DOM 구조 변경도 관찰 할 수 있습니다. 예를 들어 jsfiddle.net/4n2Gz/1을 참조하십시오 .
Tim Down

Internet Explorer 11+는 돌연변이 관찰자를 지원합니다 .
Sampson

HTML5 input이벤트가 각 상황 (특히 드래그 앤 드롭, 이탤릭체 화, 상황에 맞는 메뉴를 통해 복사 / 잘라 내기 / 붙여 넣기)에서 발생 한다는 것을 확인할 수있었습니다 (적어도 Chrome 43.0.2357.130 에서). cmd / ctrl + b와 함께 굵은 글씨체를 테스트했으며 예상 결과를 얻었습니다. 나는 또한 확인하고 있는지 확인 할 수 있었다 input이벤트가 하지 않는 명백한 보인다 (프로그램 변경에 불을하지만, 틀림없이 관련 MDN 페이지에 약간의 혼동 언어에 반하는, 무슨 뜻인지 보려면 여기를 페이지 하단을 참조하십시오 개발자 .mozilla.org / en-US / docs / Web / Events / input )
mikermcneil

22

나는 lawwantsin의 대답을 이렇게 수정했으며 이것은 나를 위해 작동합니다. 키 누르기 대신 키 업 이벤트를 사용하면 효과적입니다.

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

22

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

3
이 삭제 이벤트는 무엇입니까?
제임스 고양이

7

두 가지 옵션 :

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

7

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


2
이것은 흥미로워 보인다. 누군가 설명 할 수 있습니까? 😇
WoIIe

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

3

이 주제는 내가 주제를 조사하는 동안 매우 도움이되었습니다.

여기에서 사용할 수있는 코드 중 일부를 jQuery 플러그인으로 수정하여 재사용 할 수있는 형태로 주로 내 요구를 충족시키기 위해하지만 다른 사람들은 contenteditable 태그를 사용하여 시작하기에 더 간단한 인터페이스에 감사 할 수 있습니다.

https://gist.github.com/3410122

최신 정보:

인기가 높아짐에 따라 플러그인은 Makesites.org에 의해 채택되었습니다 .

개발은 여기에서 계속됩니다 :

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


2

여기 내가 결국 사용하고 훌륭하게 작동하는 솔루션이 있습니다. 내용을 편집 할 수있는 한 줄 div를 사용하고 있기 때문에 $ (this) .text ()을 대신 사용합니다. 그러나 .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!');
    }
});

1

타이머와 "저장"버튼을 피하기 위해 요소에 포커스가 없으면 블러 이벤트가 발생할 수 있습니다. 그러나 요소가 실제로 초점을 맞추고 defocused 된 것이 아니라 변경되었는지 확인하려면 내용을 마지막 버전과 비교해야합니다. 또는 keydown 이벤트를 사용하여이 요소에 "dirty"플래그를 설정하십시오.


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

$("div [contenteditable=true]")의 contentEditable 있습니다 직접 또는 간접적으로 사업부의 모든 아이들을, 선택합니다.
Bruno Ferreira

1

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

해당 요소는 이제 포커스를 잃을 때까지 사용자가 편집 할 수 있습니다.


5
어, 왜 설명이없는 downvote? 이것은 답변을 작성한 사람과 나중에 답변을 읽는 사람 모두에게 장애가됩니다.
마이크 윌리스

0

contentEditable 속성을 가진 요소가 변경 될 때 onchange 이벤트가 발생하지 않습니다. 제안 된 접근 방식은 단추를 추가 하여 에디션 을 "저장" 하는 것입니다.

그런 식으로 문제를 처리하는이 플러그인을 확인하십시오.


, 십년 앞으로 후대에 대한 필요가 없습니다 버튼 "저장", 허용 대답의 jsfiddle을 확인
revelt

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 예


1
+1- DOMCharacterDataModified사용자가 기존 텍스트를 수정하면 (예 : 굵게 또는 기울임 꼴 적용) 시작되지 않습니다. DOMSubtreeModified이 경우에 더 적합합니다. 또한 기존 브라우저는 이러한 이벤트를 지원하지 않습니다.
Andy E

3
변이 이벤트는 성능 문제로 인해 w3c에 의해 감가 상각됩니다. 이 스택 오버플로 질문 에서 더 많은 것을 찾을 수 있습니다 .
jrullmann

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

원하는 경우 이벤트를 제거 / 추가 할 수도 있습니다


2
편집 가능한 컨텐츠가 길어질수록 ( innerHTML비싸다) 느리고 느려질 것 입니다. 나는 input그것이 존재 하는 이벤트를 사용하고 이와 같은 것이지만 어떤 종류의 탈퇴를 사용하는 것이 좋습니다 .
Tim Down

0

앵귤러 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 
 }
}


0

다음과 같은 간단한 해결책을 따르십시오

.ts에서 :

getContent(innerText){
  this.content = innerText;
}

.html에서 :

<div (blur)="getContent($event.target.innerHTML)" contenteditable [innerHTML]="content"></div>

-1

이 아이디어를 확인하십시오. http://pastie.org/1096892

나는 그것이 가까이 있다고 생각합니다. HTML 5는 실제로 변경 이벤트를 사양에 추가해야합니다. 유일한 문제는 콜백 함수가 내용이 실제로 $ (this) .html ()에서 업데이트되기 전에 (== $ (this) .html ()) 전에 평가한다는 것입니다. setTimeout이 작동하지 않아서 슬프다. 당신이 무슨 생각을하는지 제게 알려주세요.


키 누르기 대신 키업을 시도하십시오.
Aen Tan

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.