โทรกลับเมื่อการเปลี่ยนแปลง CSS3 เสร็จสิ้น


202

ฉันต้องการลบองค์ประกอบ (เปลี่ยนความทึบของมันเป็น 0) จากนั้นเมื่อลบองค์ประกอบออกจาก DOM

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


3
ควรคล้ายกับสิ่งนี้: stackoverflow.com/questions/6186454/…
Nicolas Modrzyk

คำตอบ:


334

สำหรับช่วงการเปลี่ยนภาพคุณสามารถใช้รายการต่อไปนี้เพื่อตรวจหาจุดสิ้นสุดของการเปลี่ยนแปลงผ่าน jQuery:

$("#someSelector").bind("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", function(){ ... });

Mozilla มีการอ้างอิงที่ดีเยี่ยม:

https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions#Detecting_the_start_and_completion_of_a_transition

สำหรับภาพเคลื่อนไหวมันคล้ายกันมาก:

$("#someSelector").bind("animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd", function(){ ... });

โปรดทราบว่าคุณสามารถส่งผ่านสตริงเหตุการณ์ทั้งหมดนำหน้าเบราว์เซอร์ไปยังวิธีการผูก () พร้อมกันเพื่อสนับสนุนการยิงเหตุการณ์ในเบราว์เซอร์ทั้งหมดที่สนับสนุน

ปรับปรุง:

ตามข้อคิดเห็นโดย Duck: คุณใช้.one()วิธีการของ jQuery เพื่อให้แน่ใจว่า handler ยิงเพียงครั้งเดียว ตัวอย่างเช่น:

$("#someSelector").one("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", function(){ ... });

$("#someSelector").one("animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd", function(){ ... });

อัปเดต 2:

jQuery bind()วิธีการได้รับการคัดค้านและวิธีการที่เป็นที่ต้องการของon()jQuery 1.7bind()

นอกจากนี้คุณยังสามารถใช้off()วิธีการในฟังก์ชั่นการโทรกลับเพื่อให้แน่ใจว่ามันจะถูกยิงเพียงครั้งเดียว นี่คือตัวอย่างที่เทียบเท่ากับการใช้one()วิธีการ:

$("#someSelector")
.on("animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd",
 function(e){
    // do something here
    $(this).off(e);
 });

อ้างอิง:


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

22
@Lev คุณสามารถลดปัญหานี้ได้อย่างง่ายดายโดยการเปรียบเทียบ currentTarget ของกิจกรรมกับเป้าหมาย ดังนั้นสิ่งที่ชอบ: function (event) {if (event.target === event.currentTarget) {/ * Do stuff * /}}
Jim Jeffers

5
ใช่ฉันคิดว่าไม่นานหลังจากที่ฉันเขียนความคิดเห็น > _ <ขอบคุณที่โพสต์ ฉันแน่ใจว่ามันจะช่วยให้ผู้อื่น! :)
เลฟ

9
เราใช้.on()แทน.bind()jQuery v1.7 + api.jquery.com/bind
olo

4
เบราว์เซอร์ที่ทันสมัยทั้งหมดนี้รองรับเหตุการณ์ที่ไม่ได้รับการแก้ไข caniuse.com/#feat=css-transitions โปรดทราบว่าหากคุณมี "transitionend webkitTransitionEnd" จะมีการเรียกใช้สองครั้งใน Chrome
Michael S.

17

อีกตัวเลือกหนึ่งคือใช้jQuery Transit Frameworkเพื่อจัดการการเปลี่ยน CSS3 ของคุณ การเปลี่ยน / เอฟเฟกต์ทำงานได้ดีบนอุปกรณ์มือถือและคุณไม่ต้องเพิ่มการเปลี่ยน CSS3 ยุ่ง ๆ ในไฟล์ CSS ของคุณเพื่อที่จะทำเอฟเฟกต์ภาพเคลื่อนไหว

นี่คือตัวอย่างที่จะเปลี่ยนความทึบขององค์ประกอบเป็น 0 เมื่อคุณคลิกที่มันและจะถูกลบออกเมื่อการเปลี่ยนแปลงเสร็จสมบูรณ์:

$("#element").click( function () {
    $('#element').transition({ opacity: 0 }, function () { $(this).remove(); });
});

การสาธิต JS Fiddle


การโทรกลับไม่ทำงาน - อาจเป็นเพราะการเปลี่ยนแปลงใน API ของการขนส่งที่ฉันไม่ทราบ แต่ตัวอย่างซอก็ไม่ทำงาน มันก่อให้เกิดวิธีการซ่อนก่อนที่ภาพเคลื่อนไหวจะทำงาน (ลองใช้โครเมี่ยม)
Jonathan Liuti

@JonathanLiuti ทดสอบโดยใช้ FireFox 25, IE11, Chrome 31 ทำงานได้ดี
ROFLwTIME

ใช่ @ ROFLwTIME คุณพูดถูก - ดูเหมือนว่าโครเมี่ยมของฉันจะบ้าไปแล้ว ลองเล่นซอวันนี้หลังจากการรีสตาร์ทโครเมี่ยมอย่างสมบูรณ์และทำงานได้ตามที่คาดไว้ ความผิดฉันเอง ! ขอโทษด้วยนะ
Jonathan Liuti

14

มีanimationendเหตุการณ์ที่สามารถสังเกตเห็นได้ในเอกสารที่นี่รวมถึงtransitionภาพเคลื่อนไหวcss ที่คุณสามารถใช้transitionendเหตุการณ์ได้

ไม่จำเป็นต้องมีไลบรารีเพิ่มเติมซึ่งทั้งหมดนี้ใช้งานได้กับ vanilla JS

document.getElementById("myDIV").addEventListener("transitionend", myEndFunction);
function myEndFunction() {
	this.innerHTML = "transition event ended";
}
#myDIV {transition: top 2s; position: relative; top: 0;}
div {background: #ede;cursor: pointer;padding: 20px;}
<div id="myDIV" onclick="this.style.top = '55px';">Click me to start animation.</div>


2
นี้เป็นเส้นเขตแดนคำตอบการเชื่อมโยงเท่านั้น คุณควรขยายคำตอบเพื่อรวมข้อมูลให้มากที่สุดที่นี่และใช้ลิงก์เพื่อการอ้างอิงเท่านั้น
Goodbye StackExchange

4
โหวตหนึ่งนี้เพราะมันเป็นคนแรกที่ไม่พึ่งพา jQuery ไม่มีความหมายที่จะตัดต้นไม้ทั้งต้นเป็นกิ่ง
Aaron Mason

7

สำหรับทุกคนที่สิ่งนี้อาจมีประโยชน์สำหรับนี่คือ jQuery ขึ้นอยู่กับฟังก์ชั่นที่ฉันประสบความสำเร็จกับการใช้ภาพเคลื่อนไหว CSS ผ่านชั้นเรียน CSS แล้วได้รับการโทรกลับหลังจากนั้น มันอาจไม่ทำงานอย่างสมบูรณ์เพราะฉันใช้มันในแอป Backbone.js แต่อาจมีประโยชน์

var cssAnimate = function(cssClass, callback) {
    var self = this;

    // Checks if correct animation has ended
    var setAnimationListener = function() {
        self.one(
            "webkitAnimationEnd oanimationend msAnimationEnd animationend",
            function(e) {
                if(
                    e.originalEvent.animationName == cssClass &&
                    e.target === e.currentTarget
                ) {
                    callback();
                } else {
                    setAnimationListener();
                }
            }
        );
    }

    self.addClass(cssClass);
    setAnimationListener();
}

ฉันใช้มันแบบนี้

cssAnimate.call($("#something"), "fadeIn", function() {
    console.log("Animation is complete");
    // Remove animation class name?
});

แนวคิดดั้งเดิมจากhttp://mikefowler.me/2013/11/18/page-transitions-in-backbone/

และนี่ดูเหมือนจะเป็นประโยชน์: http://api.jqueryui.com/addClass/


ปรับปรุง

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


ขอบคุณที่แบ่งปันฉันได้ใช้และเพิ่มการแก้ไข e.stopImmediatePropagation(); self.trigger(this.whichAnimationEvent()); //for purge existing event callback.apply(self);
BomAle

5

คำตอบที่ยอมรับในปัจจุบันนั้นจะยิงสองครั้งสำหรับภาพเคลื่อนไหวใน Chrome สันนิษฐานนี้เป็นเพราะตระหนักเช่นเดียวกับwebkitAnimationEnd animationEndต่อไปนี้จะยิงเพียงครั้งเดียว:

/* From Modernizr */
function whichTransitionEvent(){

    var el = document.createElement('fakeelement');
    var transitions = {
        'animation':'animationend',
        'OAnimation':'oAnimationEnd',
        'MSAnimation':'MSAnimationEnd',
        'WebkitAnimation':'webkitAnimationEnd'
    };

    for(var t in transitions){
        if( transitions.hasOwnProperty(t) && el.style[t] !== undefined ){
            return transitions[t];
        }
    }
}

$("#elementToListenTo")
    .on(whichTransitionEvent(),
        function(e){
            console.log('Transition complete!  This is the callback!');
            $(this).off(e);
        });

3
ฉันอยากจะแนะนำให้เรียกใช้ฟังก์ชัน whichAnimationEvent () แทนเนื่องจากเกี่ยวข้องกับเหตุการณ์ภาพเคลื่อนไหว
Jakob Løkke Madsen
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.