संतोषप्रद परिवर्तन की घटनाएं


359

मैं एक उपयोगकर्ता को संपादित करता है जब एक की सामग्री के एक समारोह को चलाना चाहते हैं divके साथ contenteditableविशेषता। किसी onchangeघटना के बराबर क्या है ?

मैं jQuery का उपयोग कर रहा हूँ इसलिए jQuery का उपयोग करने वाला कोई भी समाधान पसंद किया जाता है। धन्यवाद!


मैं आमतौर पर ऐसा करता हूं document.getElementById("editor").oninput = function() { ...}:।
बसज

जवाबों:


311

मैं अटैच कर श्रोताओं के लिए महत्वपूर्ण घटनाओं संपादन योग्य तत्व द्वारा चलाई हालांकि आपको लगता है कि पता होना चाहिए सुझाव देंगे, keydownऔर keypressसामग्री अपने आप बदल जाता है से पहले की घटनाओं निकाल दिया जाता है। यह सामग्री को बदलने के हर संभव साधन को कवर नहीं करेगा: उपयोगकर्ता संपादन या संदर्भ ब्राउज़र मेनू से कट, कॉपी और पेस्ट का उपयोग भी कर सकता है, इसलिए आप घटनाओं cut copyऔर pasteघटनाओं को भी संभालना चाह सकते हैं । साथ ही, उपयोगकर्ता पाठ या अन्य सामग्री को छोड़ सकता है, इसलिए वहां अधिक घटनाएं होती हैं ( mouseupउदाहरण के लिए)। आप तत्व की सामग्री को कमबैक के रूप में प्रदूषित करना चाह सकते हैं।

अद्यतन 29 अक्टूबर 2014

एचटीएमएल 5 inputघटना लंबे समय में जवाब है। लेखन के समय, यह contenteditableवर्तमान मोज़िला (फ़ायरफ़ॉक्स 14 से) और वेबिट / ब्लिंक ब्राउज़र में तत्वों के लिए समर्थित है, लेकिन आईई नहीं।

डेमो:

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(आईई 5 +, फ़ायरफ़ॉक्स है कि उन्हें समर्थन ब्राउज़रों में घटनाओं 3.0+, सफारी 3+, क्रोम)
टिम डाउन

4
आप कीप का उपयोग कर सकते हैं, और आपको समय की समस्या नहीं होगी।
Blowsie

2
@ बाल्सी: हां, लेकिन आप संभावित रूप से घटना के आग लगने से पहले ऑटो-बार-बार की-बोर्ड से होने वाले कई बदलावों को समाप्त कर सकते हैं। इस उत्तर पर विचार नहीं किए जाने वाले संपादन योग्य पाठ को बदलने के अन्य तरीके भी हैं, जैसे कि संपादन और संदर्भ मेनू के माध्यम से खींचें और छोड़ें और संपादित करें। दीर्घकालिक, यह सब एचटीएमएल 5 inputइवेंट द्वारा कवर किया जाना चाहिए ।
टिम डाउन

1
मैं डेब्यू के साथ की-अप कर रहा हूं।
एएन टैन

1
@AndroidDev मैं क्रोम testet, और इनपुट घटना के रूप में भी चश्मा के लिए आवश्यक प्रति पर निकाल दिया जाता है पेस्ट और कटौती: w3c.github.io/uievents/#events-inputevents
मछली की हड्डी

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


मेरे लिए एकदम सही काम,
कॉफ़ीस्क्रिप्ट

7
कुछ बदलाव ऐसे हैं जो इस कोड द्वारा तब तक नहीं पकड़े जाएंगे जब तक कि संतोषप्रद धुंधला न हो जाए। उदाहरण के लिए: घसीटना और गिराना, संदर्भ मेनू से काटना, और ब्राउज़र विंडो से चिपकाना। मैंने एक उदाहरण पृष्ठ सेटअप किया है जो इस कोड का उपयोग करता है जिसे आप यहां से इंटरैक्ट कर सकते हैं
jrullmann 16

@jrullmann हाँ, मुझे इस कोड में समस्याएँ तब आईं जब मैं चित्रों को खींचता या छोड़ता था क्योंकि यह इमेज लोड को नहीं सुनता है (यह मेरे मामले में एक रिसाइज़ ऑपरेशन को संभालने के लिए एक समस्या थी)
सेबस्टियन लम्बर

@jrullmann बहुत अच्छा है, यह तब भी जावास्क्रिप्ट के साथ बदलते मूल्य पर काम करता है, कंसोल में प्रयास करें document.getElementById('editor_input').innerHTML = 'ssss':।

1
@NADB यह नहीं होना चाहिए, जैसा कि "अगर ($ this.data ('पहले')! == $ this.html ()) {" के लिए है
balupton

52

MutationObserver का उपयोग करने पर विचार करें । इन पर्यवेक्षकों को DOM में परिवर्तन के लिए प्रतिक्रिया करने के लिए, और उत्परिवर्तन घटनाओं के लिए एक प्रतिस्थापन के रूप में डिज़ाइन किया गया है ।

पेशेवरों:

  • कोई भी परिवर्तन होने पर आग लग जाती है, जो अन्य उत्तरों द्वारा सुझाए गए प्रमुख घटनाओं को सुनकर हासिल करना मुश्किल है। उदाहरण के लिए, ये सभी अच्छी तरह से काम करते हैं: संदर्भ मेनू के माध्यम से ड्रैग एंड ड्रॉप, इटैलिकाइजिंग, कॉपी / कट / पेस्ट।
  • मन में प्रदर्शन के साथ बनाया गया है।
  • सरल, सीधा कोड। कोड को समझना और डिबग करना बहुत आसान है, जो 10 घटनाओं को सुनने वाले कोड के बजाय एक घटना को सुनता है।
  • Google के पास एक उत्कृष्ट उत्परिवर्तन सारांश पुस्तकालय है जो MutationObservers का उपयोग करना बहुत आसान बनाता है।

विपक्ष:

  • फ़ायरफ़ॉक्स (14.0+), क्रोम (18+), या IE (11+) के बहुत हालिया संस्करण की आवश्यकता है।
  • समझने के लिए नई एपीआई
  • सर्वोत्तम प्रथाओं या केस स्टडी पर अभी तक बहुत सारी जानकारी उपलब्ध नहीं है

और अधिक जानें:

  • मैंने विभिन्न घटनाओं को संभालने के लिए MutationObserers का उपयोग करने के लिए तुलना करने के लिए थोड़ा स्निपेट लिखा । मैंने बलुप्टन कोड का उपयोग किया क्योंकि उसके उत्तर में सबसे अधिक अपवोट हैं।
  • मोज़िला के एपीआई पर एक उत्कृष्ट पृष्ठ है
  • MutationSummary पुस्तकालय पर एक नज़र डालें

यह HTML5 inputईवेंट (जो कि contenteditableसभी WebKit और मोज़िला ब्राउज़रों के लिए समर्थित है, जो उत्परिवर्तन पर्यवेक्षकों का समर्थन करता है) के समान नहीं है, क्योंकि DOM म्यूटेशन स्क्रिप्ट के साथ-साथ उपयोगकर्ता इनपुट के माध्यम से भी हो सकता है, लेकिन यह उन ब्राउज़रों के लिए एक व्यवहार्य समाधान है। मुझे लगता है कि यह inputघटना से भी अधिक प्रदर्शन को नुकसान पहुंचा सकता है, लेकिन मेरे पास इसके लिए कोई कठिन सबूत नहीं है।
टिम डाउन

2
+1, लेकिन क्या आपने महसूस किया है कि उत्परिवर्तन ईवेंट्स सामग्रीविहीन में लाइन फ़ीड के प्रभावों की रिपोर्ट नहीं करते हैं? अपने स्निपेट में एंटर दबाएं।
शहरकी

4
@citykid: ऐसा इसलिए है क्योंकि स्निपेट केवल चरित्र डेटा में बदलाव के लिए देख रहा है। DOM संरचनात्मक परिवर्तनों का भी निरीक्षण करना संभव है। उदाहरण के लिए jsfiddle.net/4n2Gz/1 देखें ।
टिम डाउन

इंटरनेट एक्सप्लोरर 11+ म्यूटेशन ऑब्जर्वर का समर्थन करता है ।
सैम्पसन

मैं सत्यापित करने में सक्षम था (कम से कम क्रोम 43.0.2357.130 में) कि HTML5 inputघटना इन स्थितियों में से प्रत्येक में (विशेष रूप से ड्रैग एंड ड्रॉप, इटैलिकाइजिंग, संदर्भ मेनू के माध्यम से कॉपी / कट / पेस्ट) होती है। मैंने bolding w / cmd / ctrl + b का भी परीक्षण किया और अपेक्षित परिणाम प्राप्त किए। मैंने जाँच भी की और यह सत्यापित करने में सक्षम था कि यह inputकार्यक्रम प्रोग्रामेटिक परिवर्तनों (जो स्पष्ट प्रतीत होता है, पर आग नहीं करता है), लेकिन यकीनन संबंधित एमडीएन पृष्ठ पर कुछ भ्रामक भाषा के विपरीत है, पृष्ठ का निचला भाग यहां देखें कि मेरा क्या मतलब है: डेवलपर; .mozilla.org / en-US / डॉक्स / वेब / इवेंट्स / इनपुट )
mikermcneil

22

मैंने लॉविन्सटिन के उत्तर को संशोधित किया है, इसलिए यह मेरे लिए काम करता है। मैं 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')});

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 प्लगइन में संशोधित किया है, इसलिए यह मुख्य रूप से मेरी जरूरतों को पूरा करने के लिए एक पुन: प्रयोज्य रूप में है, लेकिन अन्य लोग संतोषप्रद टैग का उपयोग करके जम्पस्टार्ट के लिए एक सरल इंटरफ़ेस की सराहना कर सकते हैं।

https://gist.github.com/3410122

अपडेट करें:

इसकी बढ़ती लोकप्रियता के कारण प्लगइन Makesites.org द्वारा अपनाया गया है

यहां से विकास जारी रहेगा:

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


2

यहाँ मैं समाधान का उपयोग कर समाप्त हो गया है और fabulously काम करता है। मैं इसके बजाय $ (यह) .text () का उपयोग करता हूं क्योंकि मैं केवल एक पंक्ति div का उपयोग कर रहा हूं जो सामग्री संपादन योग्य है। लेकिन आप .html () का भी उपयोग कर सकते हैं, इस तरह से आपको वैश्विक / गैर-वैश्विक चर के दायरे के बारे में चिंता करने की ज़रूरत नहीं है और इससे पहले वास्तव में संपादक डिव से जुड़ा हुआ है।

$('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

टाइमर और "सेव" बटन से बचने के लिए, आप ब्लर ईवेंट विच फायर का उपयोग कर सकते हैं जब तत्व फोकस खो देता है। लेकिन यह सुनिश्चित करने के लिए कि तत्व वास्तव में बदल गया था (न कि केवल ध्यान केंद्रित और विरूपित), इसकी सामग्री की तुलना इसके अंतिम संस्करण से की जानी चाहिए। या इस तत्व पर कुछ "गंदे" ध्वज सेट करने के लिए कीडाउन इवेंट का उपयोग करें।


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]")प्रत्यक्ष या अप्रत्यक्ष रूप से एक दिव्यांग के सभी बच्चों का चयन करेंगे, जो कि संतोषप्रद हैं।
ब्रूनो फरेरा

1

गैर JQuery का जवाब ...

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

इसका उपयोग करने के लिए, आईडी ("माई हैडर") के साथ एक हेडर तत्व पर कॉल करें।

makeEditable(document.getElementById('myHeader'))

वह तत्व अब उपयोगकर्ता द्वारा संपादन योग्य होगा जब तक कि वह ध्यान केंद्रित नहीं करता।


5
ऊ, क्यों कोई स्पष्टीकरण के साथ downvote? यह उत्तर लिखने वाले व्यक्ति, और उत्तर को पढ़ने वाले सभी लोगों के प्रति असहमति जताता है।
माइक विलिस

0

ऑन्चेंज इवेंट में आग नहीं लगती है जब contentEditable विशेषता वाला एक तत्व बदल जाता है, एक सुझाया दृष्टिकोण एक बटन जोड़ने के लिए हो सकता है, संस्करण को "बचाने" के लिए।

इस प्लगइन की जाँच करें जो इस तरह से समस्या को हल करता है:


दस साल बाद, आगे बढ़ने के लिए और "सेव" बटन की आवश्यकता नहीं है, स्वीकृत उत्तर के 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इस मामले में अधिक उपयुक्त है। साथ ही, लोगों को यह याद रखना चाहिए कि विरासत ब्राउज़र इन घटनाओं का समर्थन नहीं करते हैं।
एंडी ई

3
सिर्फ एक नोट कि म्यूटेशन इवेंट्स को प्रदर्शन समस्याओं की वजह से w3c द्वारा हतोत्साहित किया जाता है। इस स्टैक ओवरफ्लो प्रश्न में अधिक पाया जा सकता है ।
jrullmann 16

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घटना का उपयोग करने की सलाह दूंगा जहां यह मौजूद है और कुछ इस तरह की बहस के साथ वापस आ रही है।
टिम डाउन

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

कृपया निम्नलिखित सरल समाधान का पालन करें

Ints:

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

.html:

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

-1

इस विचार की जाँच करें। http://pastie.org/1096892

मुझे लगता है कि यह करीब है। HTML 5 को वास्तव में चेंज ईवेंट को कल्पना में जोड़ना है। एकमात्र समस्या यह है कि कॉलबैक फ़ंक्शन मूल्यांकन करता है कि क्या (= = $ (यह) .html ()) सामग्री से पहले वास्तव में $ (इस) .html () में अपडेट किया गया है। सेटटाइमआउट काम नहीं करता है, और यह दुखद है। आप क्या सोचते हैं मुझे बताओ।


की-बोर्ड की बजाए की-अप की कोशिश करें।
एएन टैन

-2

@ बालूप्टन के उत्तर के आधार पर:

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.