jQuery - เหตุการณ์ทริกเกอร์เมื่อองค์ประกอบถูกลบออกจาก DOM


211

ฉันพยายามหาวิธีใช้รหัส js เมื่อองค์ประกอบถูกลบออกจากหน้า:

jQuery('#some-element').remove(); // remove some element from the page
/* need to figure out how to independently detect the above happened */

มีเหตุการณ์ที่เหมาะกับสิ่งนั้นเช่น:

jQuery('#some-element').onremoval( function() {
    // do post-mortem stuff here
});

ขอบคุณ


1
จากความอยากรู้อยากเห็นอยากทำอะไรกับองค์ประกอบที่ถูกลบไป?
Natrium

8
ฉันมีองค์ประกอบที่ยึดติดกับตัวเองอย่างอิสระกับชิ้นส่วนที่ฉันลบดังนั้นฉันจึงต้องการตรวจสอบเมื่อชิ้นส่วนนั้นหายไปเพื่อกำจัดองค์ประกอบนั้นเช่นกัน ฉันสามารถออกแบบใหม่ทั้งหมด แต่การทำตามข้างต้นจะช่วยฉันได้มาก (และรหัส)
sa125

คำตอบ:


118

เพิ่งตรวจสอบมันมีอยู่แล้วใน JQuery เวอร์ชันปัจจุบัน:

jQuery - v1.9.1

jQuery UI - v1.10.2

$("#myDiv").on("remove", function () {
    alert("Element was removed");
})

สำคัญ : นี่คือการทำงานของสคริปต์Jquery UI (ไม่ใช่ JQuery) ดังนั้นคุณต้องโหลดทั้งสคริปต์ (jquery และ jquery-ui) เพื่อให้ทำงานได้ นี่คือตัวอย่าง: http://jsfiddle.net/72RTz/


11
สิ่งนี้มีประโยชน์มาก ฉันได้เรียนรู้ว่าฟังก์ชั่นนี้อยู่ในองค์ประกอบ "Widget" ของ jQuery UI หากคุณไม่ต้องการดาวน์โหลดไลบรารี UI ทั้งหมด
Neil

5
เอกสารนี้มีอยู่ทุกที่หรือไม่? ฉันเพิ่งดูเอกสารวิดเจ็ต jQuery UI และไม่พบการพูดถึงนี้ ต้องการที่จะเห็นว่าเรื่องนี้ได้รับการสนับสนุนอย่างเป็นทางการ / คำเตือนใด ๆ เกี่ยวกับการใช้มัน ...
Josh

อันนี้ใช้งานไม่ได้ - ลองใช้ใน jQuery 1.10.2 แต่คำตอบด้านล่างโดย @mtkopone ทำงานได้อย่างสมบูรณ์แบบดังนั้นฉันจะลงคะแนนเพื่ออัปเดตคำตอบในคำถามนั้น
Marcin

20
อันนี้ใช้ได้เพียงบางส่วนเท่านั้น หากคุณทำremoveองค์ประกอบนั้นจะทำการยิง แต่ถ้าองค์ประกอบนั้นถูกทำลายอย่างอื่นโดยการเขียนทับมันจะไม่ทำงาน
Carl Smith

คุณอาจถูกต้องอาจมีชื่อเหตุการณ์อื่นสำหรับกรณีนี้ มันจะดีถ้าคุณสามารถให้ตัวอย่าง jsfiddle สำหรับกรณีของคุณ
Philipp Munin

195

คุณสามารถใช้กิจกรรมพิเศษ jQueryสำหรับสิ่งนี้

ในทุกความเรียบง่าย

ติดตั้ง:

(function($){
  $.event.special.destroyed = {
    remove: function(o) {
      if (o.handler) {
        o.handler()
      }
    }
  }
})(jQuery)

การใช้งาน:

$('.thing').bind('destroyed', function() {
  // do stuff
})

ภาคผนวกเพื่อตอบความคิดเห็นของ Pierre และ DesignerGuy:

หากต้องการไม่มีการโทรกลับเมื่อโทรติดต่อ$('.thing').off('destroyed')ให้เปลี่ยนเงื่อนไข if เป็น:if (o.handler && o.type !== 'destroyed') { ... }


15
ทางออกที่ดีจริงๆ Ben Alman มีงานเขียนที่ดีเกี่ยวกับกิจกรรมพิเศษสำหรับข้อมูลเพิ่มเติม: benalman.com/news/2010/03/jquery-special-events
antti_s

11
+1 จัดการจนพลาดเหตุการณ์พิเศษเหล่านี้จนถึงตอนนี้มีประโยชน์มาก! สิ่งหนึ่งที่จะต้องดำเนินการตามที่กล่าวไว้ข้างต้นเป็นการดีที่สุดที่จะเปลี่ยนo.handler()เป็นo.handler.apply(this,arguments)มิฉะนั้นเหตุการณ์และวัตถุข้อมูลจะไม่ถูกส่งผ่านไปยังผู้ฟังเหตุการณ์
Pebbl

6
สิ่งนี้ไม่ทำงานเมื่อคุณลบองค์ประกอบที่ไม่มี jQuery
djjeck

5
สิ่งนี้จะไม่ทำงานก) เมื่อองค์ประกอบถูกแยกออกแทนที่จะถูกลบออกหรือข) เมื่อห้องสมุดที่ไม่ใช่ jQuery เก่าบางแห่งใช้ InnerHTML เพื่อทำลายองค์ประกอบของคุณ (คล้ายกับสิ่งที่ djjeck พูด)
Charon ME

5
ระวังตัวจัดการถูกเรียกเมื่อคุณ$('.thing').unbind('destroyed')ซึ่งอาจจะน่ารำคาญจริง ๆ (เนื่องจากการผูกมัดหมายความว่าเราไม่ต้องการให้ตัวจัดการถูกเรียก ... )
Pierre

54

คุณสามารถผูกเข้ากับเหตุการณ์ DOMNodeRemoved (เป็นส่วนหนึ่งของข้อมูลจำเพาะ DOM ระดับ 3 WC3)

ใช้งานได้ใน IE9, Firefox และ Chrome รุ่นล่าสุด

ตัวอย่าง:

$(document).bind("DOMNodeRemoved", function(e)
{
    alert("Removed: " + e.target.nodeName);
});

นอกจากนี้คุณยังสามารถรับการแจ้งเตือนเมื่อองค์ประกอบแทรกโดยผูกพัน DOMNodeInserted


13
หมายเหตุ: "การเพิ่มฟังก์ชั่นการเปลี่ยน DOM ในเอกสารจะลดประสิทธิภาพของการแก้ไข DOM เพิ่มเติมลงในเอกสารนั้นอย่างลึกซึ้ง (ทำให้ช้าลง 1.5 - 7 เท่า!)" จาก: developer.mozilla.org/en/DOM/Mutation_events
Matt Crinklaw-Vogt

1
รักสิ่งนี้แม้ว่า nodeName จะไม่ค่อยมีประโยชน์สำหรับฉัน ฉันเพียงแค่ใช้หรือe.target.className if ($(e.target).hasClass('my-class')) { ...
คาอัลคอร์น

สิ่งนี้ไม่ได้ทำงานกับองค์ประกอบเพียงอย่างเดียวเท่านั้น
Xdg

คำตอบที่น่าทึ่ง! ช่วยฉันจริงๆ!
Kir Mazur

มันอาจจะช้าและความคิดที่ดีสำหรับรหัสในการผลิต แต่นี้ดูเหมือนว่าวิธีเดียวที่ทำงานพร้อมกัน (เหมือน MutationObserver) และโหนดใด ๆ (ไม่เพียงโหนดลบออกผ่าน jQuery) นี่เป็นตัวเลือกที่ยอดเยี่ยมสำหรับการแก้ไขข้อบกพร่อง
ดำเนินงานบางอย่างของ

38

ไม่มีเหตุการณ์ในตัวสำหรับการลบองค์ประกอบ แต่คุณสามารถสร้างได้โดยวิธีการลบเริ่มต้นของ jQuery ที่ขยายออกมาปลอม โปรดทราบว่าจะต้องโทรกลับก่อนที่จะลบออกจริง ๆ เพื่อเก็บไว้อ้างอิง

(function() {
    var ev = new $.Event('remove'),
        orig = $.fn.remove;
    $.fn.remove = function() {
        $(this).trigger(ev);
        return orig.apply(this, arguments);
    }
})();

$('#some-element').bind('remove', function() {
    console.log('removed!');
    // do pre-mortem stuff here
    // 'this' is still a reference to the element, before removing it
});

// some other js code here [...]

$('#some-element').remove();

หมายเหตุ: ปัญหาบางอย่างกับคำตอบนี้ได้รับการระบุโดยผู้โพสต์อื่น ๆ

  1. สิ่งนี้จะไม่ทำงานเมื่อโหนดถูกลบผ่านhtml() replace()หรือวิธีการ jQuery อื่น ๆ
  2. เหตุการณ์นี้ทำให้เกิดฟอง
  3. jQuery UI จะลบล้างเช่นกัน

ทางออกที่ดีที่สุดสำหรับปัญหานี้น่าจะเป็น: https://stackoverflow.com/a/10172676/216941


2
ขอบคุณสำหรับสิ่งนั้น! นอกจากนี้เล็กน้อย: เนื่องจากการลบเหตุการณ์เพิ่มขึ้นคุณจะได้รับเมื่อเด็กถูกลบดังนั้นควรเขียน handler ด้วยวิธีนี้:$('#some-element').bind('remove', function(ev) { if (ev.target === this) { console.log('removed!'); } });
meyertee

3
นี่ไม่ได้ผลสำหรับฉัน - ฉันต้องส่งคืนผลลัพธ์จาก orig.apply
fturtle

1
ที่จริงแล้ว @Adam มันเป็น แต่มันเข้ากันได้กับเบราว์เซอร์ข้าม ด้วยการเพิ่มเติมของ meyertee / fturtle มันเป็นทางออกที่เชื่อถือได้อย่างสมบูรณ์แบบตราบใดที่คุณลบองค์ประกอบด้วยวิธีนี้แทนที่จะแก้ไข / ล้าง HTML เป็นต้นสำหรับสิ่งที่ยืดหยุ่นกว่านี้ใช่เหตุการณ์การกลายพันธุ์ของ DOM ทำได้ดี แต่ฉันก็สงสัยว่ามันเป็น คุณควรรับฟังกิจกรรมทางธุรกิจในแอปไม่ใช่ DOM ที่โครงสร้างมีแนวโน้มที่จะเปลี่ยนแปลงเมื่อมีการพัฒนาเพิ่มเติม นอกจากนี้การสมัครเข้าร่วมกิจกรรมการกลายพันธุ์ DOM หมายความว่าโปรแกรมของคุณอาจมีความอ่อนไหวต่อความล่าช้าในลำดับชั้น DOM ที่ซับซ้อน
Will Morgan

1
ความเห็นพ้องของฉันเกี่ยวกับความถูกต้องเพียงอย่างเดียวคือข้อความ - 'ไม่มีเหตุการณ์ในตัวสำหรับการลบองค์ประกอบ' --- มีเหตุการณ์ในตัวสำหรับเบราว์เซอร์ที่ใช้เหตุการณ์ DOM ระดับ 3 (ตามรายละเอียดในคำตอบของฉัน)
อดัม

4
แม้ว่าสิ่งนี้จะตรวจพบองค์ประกอบที่ถูกลบโดยใช้ฟังก์ชั่น 'ลบ' แต่ก็จะล้มเหลวในการตรวจสอบองค์ประกอบที่ถูกลบโดยวิธีการอื่น (เช่นการใช้ html, แทนที่, ฯลฯ ) ของ jQuery โปรดดูคำตอบของฉันสำหรับการแก้ปัญหาที่สมบูรณ์มากขึ้น
zah

32

Hooking .remove()ไม่ได้เป็นวิธีที่ดีที่สุดในการจัดการนี้เนื่องจากมีหลายวิธีในการลบองค์ประกอบจากหน้า (เช่นโดยการใช้.html(), .replace()ฯลฯ )

เพื่อป้องกันอันตรายจากการรั่วไหลของหน่วยความจำ jQuery ภายในจะพยายามเรียกใช้ฟังก์ชันjQuery.cleanData()สำหรับแต่ละองค์ประกอบที่ถูกลบโดยไม่คำนึงถึงวิธีการที่ใช้ในการลบออก

ดูคำตอบนี้สำหรับรายละเอียดเพิ่มเติม: หน่วยความจำรั่วจาวาสคริปต์

ดังนั้นเพื่อผลลัพธ์ที่ดีที่สุดคุณควรขอcleanDataฟังก์ชั่นซึ่งเป็นสิ่งที่ปลั๊กอินjquery.event.destroyedทำ:

http://v3.javascriptmvc.com/jquery/dist/jquery.event.destroyed.js


ข้อมูลเชิงลึกเกี่ยวกับเรื่องcleanDataนี้มีประโยชน์กับฉันมาก! ขอบคุณมาก Joe :)
Petr Vostrel

1
คำตอบที่ดี แต่ก็ยังใช้ได้กับวิธีการ jQuery เท่านั้น หากคุณกำลังผสานรวมกับแพลตฟอร์มอื่นที่สามารถ "ดึงพรมออก" จากคุณ - คำตอบของอดัมเหมาะสมที่สุด
Bron Davies

7

สำหรับผู้ที่ใช้ jQuery UI:

jQuery UI ได้แทนที่บางส่วนของวิธี jQuery ในการดำเนินการremoveจัดกิจกรรมที่ได้รับการจัดการที่ไม่เพียง แต่เมื่อคุณอย่างชัดเจนลบองค์ประกอบที่กำหนด แต่ยังถ้าองค์ประกอบที่ได้รับการลบออกจาก DOM โดยการทำความสะอาดด้วยตนเองวิธีการใด ๆ jQuery (เช่นreplace, htmlฯลฯ ) . สิ่งนี้ช่วยให้คุณสามารถใส่ตะขอเข้าไปในเหตุการณ์เดียวกันที่ถูกไล่ออกเมื่อ jQuery กำลัง "ล้าง" เหตุการณ์และข้อมูลที่เกี่ยวข้องกับองค์ประกอบ DOM

John Resig ได้ระบุว่าเขาเปิดรับแนวคิดของการนำเหตุการณ์นี้ไปใช้ใน jQuery core รุ่นต่อไปในอนาคต แต่ฉันไม่แน่ใจว่าจะใช้งานที่ใดในปัจจุบัน


6

ต้องการ jQuery เท่านั้น (ไม่ต้องการ jQuery UI)

( ฉันได้แยกส่วนขยายนี้ออกจากเฟรมเวิร์ก jQuery UI )

ทำงานร่วมกับ: empty()และhtml()และremove()

$.cleanData = ( function( orig ) {
    return function( elems ) {
        var events, elem, i;
        for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) {
            try {

                // Only trigger remove when necessary to save time
                events = $._data( elem, "events" );
                if ( events && events.remove ) {
                    $( elem ).triggerHandler( "remove" );
                }

            // Http://bugs.jquery.com/ticket/8235
            } catch ( e ) {}
        }
        orig( elems );
    };
} )( $.cleanData );

ด้วยโซลูชันนี้คุณสามารถยกเลิกการผูกตัวจัดการเหตุการณ์ได้

$("YourElemSelector").off("remove");

ลองมัน! - ตัวอย่าง

$.cleanData = (function(orig) {
  return function(elems) {
    var events, elem, i;
    for (i = 0;
      (elem = elems[i]) != null; i++) {
      try {

        // Only trigger remove when necessary to save time
        events = $._data(elem, "events");
        if (events && events.remove) {
          $(elem).triggerHandler("remove");
        }

        // Http://bugs.jquery.com/ticket/8235
      } catch (e) {}
    }
    orig(elems);
  };
})($.cleanData);


$("#DivToBeRemoved").on("remove", function() {
  console.log("div was removed event fired");
});

$("p").on("remove", function() {
  console.log("p was removed event fired");
});

$("span").on("remove", function() {
  console.log("span was removed event fired");
});

// $("span").off("remove");

$("#DivToBeRemoved").on("click", function() {
  console.log("Div was clicked");
});

function RemoveDiv() {
  //       $("#DivToBeRemoved").parent().html("");    
  $("#DivToBeRemoved").remove();
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h3>OnRemove event handler attached to elements `div`, `p` and `span`.</h3>
<div class="container">
  <br>
  <button onclick="RemoveDiv();">Click here to remove div below</button>
  <div id="DivToBeRemoved">
    DIV TO BE REMOVED 
    contains 1 p element 
    which in turn contains a span element
    <p>i am p (within div)
      <br><br><span>i am span (within div)</span></p>
  </div>
</div>

การสาธิตเพิ่มเติม- jsBin


4

ฉันไม่สามารถรับคำตอบนี้เพื่อทำงานกับการไม่ผูกมัด (แม้จะมีการอัปเดตดูที่นี่ ) แต่ก็สามารถหาวิธีแก้ไขได้ คำตอบคือการสร้างกิจกรรมพิเศษ 'destroy_proxy' ที่เรียกใช้เหตุการณ์ 'ทำลาย' คุณใส่ผู้ฟังเหตุการณ์ทั้งใน 'destroy_proxy' และ 'ถูกทำลาย' จากนั้นเมื่อคุณต้องการที่จะยกเลิกการผูกคุณเพียงแค่ผูกเหตุการณ์ 'ถูกทำลาย':

var count = 1;
(function ($) {
    $.event.special.destroyed_proxy = {
        remove: function (o) {
            $(this).trigger('destroyed');
        }
    }
})(jQuery)

$('.remove').on('click', function () {
    $(this).parent().remove();
});

$('li').on('destroyed_proxy destroyed', function () {
    console.log('Element removed');
    if (count > 2) {
        $('li').off('destroyed');
        console.log('unbinded');
    }
    count++;
});

นี่คือซอ


สิ่งที่เกี่ยวกับความเข้ากันได้ของเบราว์เซอร์ที่นี่? มันยังใช้งานได้หรือไม่
Vladislav Rastrusny

3

ฉันชอบคำตอบของ mtkopone โดยใช้เหตุการณ์พิเศษ jQuery แต่โปรดทราบว่ามันไม่ทำงานก) เมื่อองค์ประกอบถูกแยกออกแทนที่จะลบออกหรือข) เมื่อห้องสมุดที่ไม่ใช่ jquery เก่าบางแห่งใช้ InnerHTML เพื่อทำลายองค์ประกอบของคุณ


3
ฉันลงคะแนนเนื่องจากคำถามที่ถามเพื่อการใช้. Remove () อย่างชัดเจนไม่ใช่การถอดออก detachมีการใช้โดยเฉพาะอย่างยิ่งเพื่อไม่ทริกเกอร์การล้างข้อมูลเนื่องจากองค์ประกอบอาจมีการวางแผนที่จะติดตั้งใหม่ในภายหลัง b) ยังคงเป็นจริงและยังไม่มีการจัดการที่เชื่อถือได้อย่างน้อยที่สุดเนื่องจากเหตุการณ์การกลายพันธุ์ของ DOM ถูกนำไปใช้อย่างกว้างขวาง
Pierre

4
ฉันพนันได้เลยว่าคุณทำแบบนี้เพื่อรับตรา "นักวิจารณ์";)
Charon ME

1

ฉันไม่แน่ใจว่ามีการจัดการเหตุการณ์สำหรับสิ่งนี้ดังนั้นคุณจะต้องเก็บสำเนาของ DOM และเปรียบเทียบกับ DOM ที่มีอยู่ในการวนโพลบางประเภท - ซึ่งอาจน่ารังเกียจทีเดียว Firebug ทำเช่นนี้ - หากคุณตรวจสอบ HTML และเรียกใช้การเปลี่ยนแปลง DOM บางอย่างมันจะเน้นการเปลี่ยนแปลงสีเหลืองในคอนโซล Firebug ในช่วงเวลาสั้น ๆ

หรือคุณสามารถสร้างฟังก์ชั่นลบ ...

var removeElements = function(selector) {
    var elems = jQuery(selector);

    // Your code to notify the removal of the element here...
    alert(elems.length + " elements removed");

    jQuery(selector).remove();
};

// Sample usage
removeElements("#some-element");
removeElements("p");
removeElements(".myclass");

1
+1 สำหรับแนวคิดนี้ แม้ว่าคุณสามารถขยาย jQuery (สไตล์ปลั๊กอิน) เพื่อรับการเรียก jQuery มาตรฐานเพิ่มเติมเช่น: $ ('. itemToRemove'). customRemove () ;. คุณสามารถสร้างมันเพื่อให้มันรับการเรียกกลับเป็นพารามิเตอร์
user113716

1

นี่คือวิธีการสร้างฟัง jQuery live remove :

$(document).on('DOMNodeRemoved', function(e)
{
  var $element = $(e.target).find('.element');
  if ($element.length)
  {
    // do anything with $element
  }
});

หรือ:

$(document).on('DOMNodeRemoved', function(e)
{
  $(e.target).find('.element').each(function()
  {
    // do anything with $(this)
  }
});

1
มันจะเป็นการดีถ้าคุณมีอิสระที่จะทำเช่นนั้น น่าเสียดายที่มันไม่น่าเชื่อถือเนื่องจากเหตุการณ์การกลายพันธุ์ถูกเลิกใช้งานแล้ว: developer.mozilla.org/en-US/docs/Web/Guide/Events/ …
Kamafeather

1

เหตุการณ์ "ลบ" จาก jQuery ทำงานได้ดีโดยไม่ต้องเพิ่ม มันอาจจะเชื่อถือได้มากขึ้นในเวลาที่ใช้เคล็ดลับง่าย ๆ แทนที่จะทำการแพตช์ jQuery

เพียงแค่ปรับเปลี่ยนหรือเพิ่มคุณสมบัติในองค์ประกอบที่คุณกำลังจะลบออกจาก DOM ดังนั้นคุณสามารถเรียกใช้ฟังก์ชั่นการอัพเดทใด ๆ ที่จะเพิกเฉยองค์ประกอบที่จะถูกทำลายโดยมีแอตทริบิวต์ "do_not_count_it"

สมมติว่าเรามีตารางที่มีเซลล์ที่สอดคล้องกับราคาและคุณต้องแสดงเฉพาะราคาสุดท้าย: นี่คือตัวเลือกที่จะทริกเกอร์เมื่อเซลล์ราคาถูกลบ (เรามีปุ่มในแต่ละบรรทัดของตารางที่ไม่แสดง ที่นี่)

$('td[validity="count_it"]').on("remove", function () {
    $(this).attr("validity","do_not_count_it");
    update_prices();
});

และนี่คือฟังก์ชันที่ค้นหาราคาสุดท้ายในตารางโดยไม่คำนึงถึงราคาล่าสุดหากเป็นราคาที่ถูกลบออก แน่นอนเมื่อเหตุการณ์ "ลบ" ถูกทริกเกอร์และเมื่อเรียกใช้ฟังก์ชันนี้องค์ประกอบจะไม่ถูกลบออก

function update_prices(){
      var mytable=$("#pricestable");
      var lastpricecell = mytable.find('td[validity="count_it"]').last();
}

ในที่สุดฟังก์ชัน update_prices () จะทำงานได้ดีหลังจากนั้นองค์ประกอบ DOM จะถูกลบออก


0

การอ้างอิงถึง @David คำตอบ:

เมื่อคุณต้องการทำเช่นเดียวกันกับฟังก์ชั่นอื่นเช่น html () เหมือนในกรณีของฉันอย่าลืมที่จะเพิ่มผลตอบแทนในฟังก์ชั่นใหม่:

(function() {
    var ev = new $.Event('html'),
        orig = $.fn.html;
    $.fn.html = function() {
        $(this).trigger(ev);
        return orig.apply(this, arguments);
    }
})();

0

นี้.

$.each(
  $('#some-element'), 
        function(i, item){
            item.addEventListener('DOMNodeRemovedFromDocument',
                function(e){ console.log('I has been removed'); console.log(e);
                })
         })

1
ดูเหมือนว่า DOMNodeRemovedFromDocument ใน Firefox จะไม่รองรับ อาจลองใช้MutationObserverแทน
EricP

0

ส่วนขยายของคำตอบของอดัมในกรณีที่คุณจำเป็นต้องเริ่มต้นต่อไปนี้เป็นวิธีแก้ไข:

$(document).on('DOMNodeRemoved', function(e){
        if($(e.target).hasClass('my-elm') && !e.target.hasAttribute('is-clone')){
            let clone = $(e.target).clone();
            $(clone).attr('is-clone', ''); //allows the clone to be removed without triggering the function again

            //you can do stuff to clone here (ex: add a fade animation)

            $(clone).insertAfter(e.target);
            setTimeout(() => {
                //optional remove clone after 1 second
                $(clone).remove();
            }, 1000);
        }
    });

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.