ค้นหาเว็บไซต์

typescript - แอนิเมชันการเปลี่ยนหน้าด้วย Angular 2.0 router และสัญญาอินเทอร์เฟซคอมโพเนนต์


ใน Angular 1.x เราสามารถใช้ ngAnimate เพื่อตรวจสอบเมื่อเรากำลังออกจากหรือเข้าสู่เส้นทางเฉพาะ นอกจากนี้ เรายังสามารถใช้พฤติกรรมกับพวกมันได้:

animateApp.animation('.myElement', function(){

    return {

        enter : function(element, done) {
            //Do something on enter
        },

        leave : function(element, done) {
            //Do something on leave
        }
    };

)};

ส่งผลให้ได้ผลิตภัณฑ์เช่นนี้: http://embed.plnkr.co/uW4v9T/preview

ฉันอยากทำบางสิ่งที่คล้ายกันกับ Angular 2.0 และฉันรู้สึกว่าฉันค่อนข้างใกล้แล้ว...

ดังนั้นนี่คือสิ่งที่เกิดขึ้น ฉันได้สร้างเราเตอร์ง่ายๆ ในคอมโพเนนต์แอปพลิเคชันหลักที่ควบคุมการนำทางระหว่างคอมโพเนนต์ home และ about

import { bootstrap, bind, Component, provide, View } from 'angular2/angular2';
import {RouteConfig, RouteParams, ROUTER_DIRECTIVES, ROUTER_PROVIDERS, APP_BASE_HREF, ROUTER_BINDINGS} from 'angular2/router'




/////////////////////////////////////////////////////////////////
// Home Component Start
/////////////////////////////////////////////////////////////////
@Component({
  selector: 'home-cmp'
})

@View({
  template: `
    <h2 class="title">Home Page</h2>
  `
})

class HomeCmp implements OnActivate, onDeactivate{

  onActivate(next: ComponentInstruction, prev: ComponentInstruction) {
    console.log("Home Page - initialized");
  }

  onDeactivate(next: ComponentInstruction, prev: ComponentInstruction) {
    console.log("Home Page - destroyed");
  }

}
/////////////////////////////////////////////////////////////////
// Home Component End
/////////////////////////////////////////////////////////////////




/////////////////////////////////////////////////////////////////
// About Component Start
/////////////////////////////////////////////////////////////////
@Component({
  selector: 'about-cmp'
})

@View({
  template: `
    <h2 class="title">About Page</h2>
  `
})

class AboutCmp implements OnActivate, onDeactivate {

  onActivate(next: ComponentInstruction, prev: ComponentInstruction) {
    console.log("About Page - initialized");
  }

  onDeactivate(next: ComponentInstruction, prev: ComponentInstruction) {
    console.log("About Page - destroyed");
  }

}
/////////////////////////////////////////////////////////////////
// About Component End
/////////////////////////////////////////////////////////////////




/////////////////////////////////////////////////////////////////
// Main Application Componenent Start
/////////////////////////////////////////////////////////////////
@Component({
  selector: 'my-app'
})

@View({
  template: `
    <div>
      <h1>Hello {{message}}!</h1>
      <a [router-link]="['./HomeCmp']">home</a>
      <a [router-link]="['./AboutCmp']">about</a>
      <hr>
      <router-outlet></router-outlet>
    </div>
  `,
  directives: [ROUTER_DIRECTIVES]
})

@RouteConfig([
  {path: '/', component: HomeCmp, as: 'HomeCmp'},
  {path: '/about', component: AboutCmp, as: 'AboutCmp'}
])

export class App {
}
/////////////////////////////////////////////////////////////////
// Main Application Componenent End
/////////////////////////////////////////////////////////////////




bootstrap(App, [
  ROUTER_BINDINGS,
  ROUTER_PROVIDERS,
  ROUTER_DIRECTIVES,
  provide(APP_BASE_HREF, {useValue: '/'})
])

ในตอนนี้ฉันสามารถจับได้เมื่อเราเตอร์ได้สร้างหรือทำลายคอมโพเนนต์ใด ๆ เมื่อมันย้ายจากอันหนึ่งไปยังอีกอันหนึ่ง ซึ่งนั่นดีมาก แต่เมื่อคอมโพเนนต์ ก่อนหน้า ถูก ทำลาย ฉันไม่สามารถใช้แอนิเมชันการเปลี่ยนผ่าน เมื่อออก ก่อนที่คอมโพเนนต์ถัดไปจะถูกเริ่มต้นได้

class HomeCmp implements OnActivate, onDeactivate{

    onActivate(next: ComponentInstruction, prev: ComponentInstruction) {
        //This works
        TweenMax.fromTo($(".title"), 1, {opacity: 0}, {opacity: 1});
    }

    onDeactivate(next: ComponentInstruction, prev: ComponentInstruction) {
        //This get ignored
        TweenMax.fromTo($(".title"), 1, {opacity: 0}, {opacity: 1});
    }

}

ดูเหมือนว่าจะมีวิธีแก้ปัญหานี้โดยใช้ promises ในการพรีวิว API ของ Angular.io พวกเขาระบุว่า:

ถ้า onDeactivate คืนค่า promise การเปลี่ยนเส้นทางจะรอจนกว่า promise นั้นจะเสร็จสิ้น

และ

หาก onActivate ส่งคืน promise การเปลี่ยนเส้นทางจะรอจนกว่า promise จะเสร็จสิ้นก่อนที่จะสร้างและเปิดใช้งานคอมโพเนนต์ลูก

https://angular.io/docs/ts/latest/api/

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

onDeactivate(next: ComponentInstruction, prev: ComponentInstruction) {

    function ani(){
      TweenMax.fromTo($(".title"), 1, {opacity: 1}, {opacity: 0});
    }

    var aniPromise = ani();

    aniPromise.then(function (ani) {
        ani();
    });

}

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

ฉันหวังว่าทุกอย่างจะเข้าใจได้ และฉันขอบคุณสำหรับความช่วยเหลือจริงๆ!

คำตอบ #1

ตามที่คุณอ้างจากเอกสาร หาก hooks ใดๆ เหล่านี้ส่งค่ากลับเป็น Promise มันจะรอจนกว่าจะเสร็จสิ้นก่อนที่จะไปยังอันถัดไป ดังนั้นคุณสามารถส่งค่ากลับเป็น Promise ที่แทบจะไม่ทำอะไรเลยแล้วรอหนึ่งวินาที (หรือกี่เวลาที่คุณต้องการ) ได้อย่างง่ายดาย

 onActivate(next: ComponentInstruction, prev: ComponentInstruction) {
    TweenMax.fromTo($(".title"), 1, {opacity: 0}, {opacity: 1});
    return new Promise((res, rej) => setTimeout(() => res(1), 1000));
  }

  onDeactivate(next: ComponentInstruction, prev: ComponentInstruction) {
    TweenMax.fromTo($(".title"), 1, {opacity:1}, {opacity: 0});
    return new Promise((res, rej) => setTimeout(() => res(1), 1000));
  }

โปรดทราบว่าฉันกำลังส่งคืน Promise ซึ่งรัน setTimeout เรารอหนึ่งวินาทีเพื่อให้เวลาแอนิเมชันเพียงพอที่จะเสร็จสมบูรณ์

ฉันไม่ค่อยชอบใช้ setTimeouts เท่าไหร่ ดังนั้นเราสามารถใช้ Observables ได้เช่นกัน ซึ่งส่วนตัวฉันชอบมากที่สุด

return Rx.Observable.of(true).delay(1000).toPromise();

ที่นี่ฉันกำลังส่งค่าที่สุ่มขึ้นมา (ในกรณีนี้คือ true) และหน่วงเวลาไว้หนึ่งวินาที และสุดท้ายก็แปลงมันเป็น Promise ใช่ มันก็จะกลายเป็น Promise แต่ฉันไม่ได้ใช้มันโดยตรง

นี่คือ plnkr ที่มีตัวอย่างการทำงาน (คาดว่าจะเป็นสิ่งที่คุณกำลังมองหา)

ป.ล.: ถ้าเป็นบางครั้งมันบ่นเกี่ยวกับการที่มันไม่พบเส้นทางไปยัง Rx ให้ทำการรีเฟรชไปเรื่อยๆ จนกว่าจะใช้งานได้ (ฉันได้เพิ่ม Rx.js ด้วยตัวเอง และดูเหมือนว่ามันจะหนักสำหรับ plnkr เล็กน้อย)

คำตอบ #2

โซลูชันสุดท้ายของ Angular 2:

พลั๊ง

โดยสรุป เราสามารถใช้คำสั่งในตัว @routeAnimation เพื่อทำสิ่งนี้ แต่ละคอมโพเนนต์ของเราที่แทนเส้นทางย่อยจะถูกตกแต่งด้วยบางอย่างเช่น:

@Component({
  selector: 'app-pageone'
  host: { '[@routeAnimation]': 'true' },
  styles: [':host { width: 300px; display: block; position: absolute; }']
  animations: [
    trigger('routeAnimation', [
      state('*', style({transform: 'translateX(0)', opacity: 1})),
      transition('void => *', [
        style({transform: 'translateX(-100%)', opacity: 0}),
        animate('0.5s cubic-bezier(0.215, 0.610, 0.355, 1.000)')
      ]),
      transition('* => void',
        animate('0.5s cubic-bezier(0.215, 0.610, 0.355, 1.000)', style({
          transform: 'translateX(100%)',
          opacity: 0
        }))
      )
    ])
  ]
})

บทความที่เกี่ยวข้อง