如何根据不同的路由来源执行不同的转场动画
====================

#### 问题现象

设置转场动画时，如何根据来源页面的不同执行不同的转场动画？例如A页面跳转B页面时执行一种动画，C页面跳转B页面时执行另一种动画。

#### 效果预览

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/c0/v3/Cg2cuFhNRTCvYvYZ9fwm9w/zh-cn_image_0000002658926437.png?HW-CC-KV=V1&HW-CC-Date=20260709T134110Z&HW-CC-Expire=86400&HW-CC-Sign=B6FE597FA66B9C26FFB8AF7E312F9EC9FCCBA59B5E5E3417A9BF0F21B6739883 "点击放大")

#### 背景知识

*   [pageTransition](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-page-transition-animation)是页面间转场动画，包括入场动画PageTransitionEnter和离场动画PageTransitionExit。
*   [Router](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-uicontext-router)路由可以在跳转时通过params参数传递数据，并通过[getParams](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-uicontext-router#getparams)获取传递的数据。
*   [customNavContentTransition](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-navigation#customnavcontenttransition11)是Navigation路由下的转场动画设置，可以直接通过参数from，to的方式定义具体两个页面直接的转场动画。

#### 解决方案

*   **场景一**：Navigation导航下的实现方式。
    
    参考官网[示例13（自定义转场动画）](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-navigation#示例13自定义转场动画)，通过from，to的方式即可根据不同的路由来源执行不同的转场动画。
    
*   **场景二**：Router导航下的实现方式。
    
    以入场动画为例：从Index页面进入Page1时，执行一个平移的入场动画，从Page2进入Page1时，执行一个缩放的入场动画。
    
    1.  定义用于控制动画执行的参数类。
        
        class TransitionTranslateClass {
          x?: number | string;
          y?: number | string;
          z?: number | string;
        
          constructor(x?: number | string, y?: number | string, z?: number | string,) {
            this.x = x;
            this.y = y;
            this.z = z;
          }
        }
        
        class TransitionScaleClass {
          x?: number;
          y?: number;
          z?: number;
          centerX?: number | string;
          centerY?: number | string;
        
          constructor(x?: number, y?: number, z?: number, centerX?: number | string, centerY?: number | string) {
            this.x = x;
            this.y = y;
            this.z = z;
            this.centerX = centerX;
            this.centerY = centerY;
          }
        }
        
    2.  在组件中创建参数类的实例，并通过该实例执行动画。
        
        transitionTranslate: TransitionTranslateClass = new TransitionTranslateClass();
        transitionScale: TransitionScaleClass = new TransitionScaleClass();
        
        pageTransition() {
          PageTransitionEnter({ duration: 1200, curve: Curve.Linear })
            .slide(this.transitionSlide)
            .opacity(this.transitionOpacity)
            .translate(this.transitionTranslate)
            .scale(this.transitionScale)
            .onEnter((type: RouteType) => {
              if (type === RouteType.Push || type === RouteType.Pop) {
              }
            });
        }
        
    3.  通过getParam获取的参数，决定给哪个参数类实例赋怎样的值，当不赋值时，对应的实例为undefined，因此不执行对应的动画效果。
        
        onPageShow(): void {
          let params = this.getUIContext().getRouter().getParams() as Record<string, string | number>;
          let data: string = params?.data as string;
          if (data === 'Index') {
            this.transitionTranslate = new TransitionTranslateClass(30, 30, 30);
          } else if (data === 'Page2') {
            this.transitionScale = new TransitionScaleClass(2, 2, 2);
          }
        }
        
    
    完整示例参考如下：
    
    _// Index.ets_
    @Entry
    @Component
    struct Index {
      build() {
        RelativeContainer() {
          Text('Index')
            .fontSize($r('app.float.page\_text\_font\_size'))
            .fontWeight(FontWeight.Bold)
            .alignRules({
              center: { anchor: '\_\_container\_\_', align: VerticalAlign.Center },
              middle: { anchor: '\_\_container\_\_', align: HorizontalAlign.Center }
            })
            .onClick(() => {
              this.getUIContext().getRouter().pushUrl({ url: 'pages/Page1', params: { data: 'Index' } });
            });
        }
        .height('100%')
        .width('100%');
      }
    }
    
    _// Page1.ets_
    class TransitionTranslateClass {
      x?: number | string;
      y?: number | string;
      z?: number | string;
    
      constructor(x?: number | string, y?: number | string, z?: number | string,) {
        this.x = x;
        this.y = y;
        this.z = z;
      }
    }
    
    class TransitionScaleClass {
      x?: number;
      y?: number;
      z?: number;
      centerX?: number | string;
      centerY?: number | string;
    
      constructor(x?: number, y?: number, z?: number, centerX?: number | string, centerY?: number | string) {
        this.x = x;
        this.y = y;
        this.z = z;
        this.centerX = centerX;
        this.centerY = centerY;
      }
    }
    
    @Entry
    @Component
    struct Page1 {
      transitionSlide: SlideEffect = 0;
      transitionOpacity: number = 1;
      transitionTranslate: TransitionTranslateClass = new TransitionTranslateClass();
      transitionScale: TransitionScaleClass = new TransitionScaleClass();
    
      onPageShow(): void {
        let params = this.getUIContext().getRouter().getParams() as Record<string, string | number>;
        let data: string = params?.data as string;
        if (data === 'Index') {
          this.transitionTranslate = new TransitionTranslateClass(30, 30, 30);
        } else if (data === 'Page2') {
          this.transitionScale = new TransitionScaleClass(2, 2, 2);
        }
      }
    
      build() {
        RelativeContainer() {
          Text('Page1')
            .fontSize($r('app.float.page\_text\_font\_size'))
            .fontWeight(FontWeight.Bold)
            .alignRules({
              center: { anchor: '\_\_container\_\_', align: VerticalAlign.Center },
              middle: { anchor: '\_\_container\_\_', align: HorizontalAlign.Center }
            })
            .onClick(() => {
              this.getUIContext().getRouter().pushUrl({ url: 'pages/Page2' });
            });
        }
        .height('100%')
        .width('100%');
      }
    
      pageTransition() {
        PageTransitionEnter({ duration: 1200, curve: Curve.Linear })
          .slide(this.transitionSlide)
          .opacity(this.transitionOpacity)
          .translate(this.transitionTranslate)
          .scale(this.transitionScale)
          .onEnter((type: RouteType) => {
            if (type === RouteType.Push || type === RouteType.Pop) {
            }
          });
      }
    }
    
    _// Page2.ets_
    @Entry
    @Component
    struct Page2 {
      build() {
        RelativeContainer() {
          Text('Page2')
            .fontSize($r('app.float.page\_text\_font\_size'))
            .fontWeight(FontWeight.Bold)
            .alignRules({
              center: { anchor: '\_\_container\_\_', align: VerticalAlign.Center },
              middle: { anchor: '\_\_container\_\_', align: HorizontalAlign.Center }
            })
            .onClick(() => {
              this.getUIContext().getRouter().pushUrl({ url: 'pages/Page1', params: { data: 'Page2' } });
            });
        }
        .height('100%')
        .width('100%');
      }
    }
    
    main\_pages.json文件配置：
    
    {
      "src": \[
        "pages/Index",
        "pages/Page1",
        "pages/Page2"
      \]
    }