【问题标题】:Ionic override all BACK button behaviour for specific controller离子覆盖特定控制器的所有 BACK 按钮行为
【发布时间】:2015-11-20 19:04:27
【问题描述】:

我希望能够覆盖导航栏上的 BACK 按钮和硬件按钮。

我希望此覆盖适用于一个特定的控制器,而不适用于其他控制器。

  • 当用户移动到另一个屏幕时必须取消它

(使用 ionic v1.0.0 uranium-unicorn)


我的原因是我有一个项目清单。单击列表会打开一个详细信息页面,其中包含 3 个选项卡。每个选项卡共享同一个控制器。

但是,在任何这些选项卡上按 BACK 都必须返回到主列表。这就是它在本机设备上的工作方式,所以我希望它在我的混合应用程序上工作。


许多在线提供的解决方案似乎是针对较旧的 beta 版本,或用于在控制器之外注册。

在控制器内使用 Android 硬件按钮的常见解决方案是:

$ionicPlatform.registerBackButtonAction(function (event) {
  if($state.current.name=="home"){
    alert("button back");
  }
}, 100);

但这似乎不适用于软导航栏按钮,它适用于所有控制器,而不仅仅是一个。

【问题讨论】:

  • 相关问题无工作解决方案:Ionic: How to override back button function?
  • 如果您希望能够覆盖 ion-nav-back-button 意味着您必须使用 ionicbundle.js 中的代码覆盖模块 ionnavbackbutton ,并且可以将硬件后退按钮覆盖为 $ ionicPlatform.registerBackButtonAction(function () { if ($state.current.name == "home"){ navigator.app.exitApp(); } else { navigator.app.backHistory(); } }, 100);跨度>

标签: ionic-framework ionic


【解决方案1】:

对于那些使用最新版本的电容器和离子的人来说,这很有效:

import { Capacitor } from "@capacitor/core";
import { App as CapacitorApp } from "@capacitor/app";

const App: React.FC = () => {
  const history = useHistory();
  useEffect(() => {
    if (Capacitor.isNativePlatform()) {
      CapacitorApp.addListener("backButton", () => {
        history.goBack();
      });
    }
  });

  return (
    <IonApp>...

【讨论】:

    【解决方案2】:

    接受@raven.zuo 的反馈并进行了一些修改以取消注册状态更改事件。

    (function () {
        'use strict';
    
        angular
            .module('appName')
            .service('customBackButtonService', customBackButtonService);
    
        customBackButtonService.$inject = ['$rootScope', '$ionicPlatform'];
        function customBackButtonService($rootScope, $ionicPlatform) {
    
            var service = {
                setup: setup
            };
    
            return service;
    
            ////////////////
    
            function setup(customBackFunction) {
                // override soft back
                // framework calls $rootScope.$ionicGoBack when soft back button is pressed
                $rootScope.oldSoftBack = $rootScope.$ionicGoBack;
                $rootScope.$ionicGoBack = function () {
                    customBackFunction();
                };
                var deregisterSoftBack = function () {
                    $rootScope.$ionicGoBack = $rootScope.oldSoftBack;
                };
    
                // override hard back
                // registerBackButtonAction() returns a function which can be used to deregister it
                var deregisterHardBack = $ionicPlatform.registerBackButtonAction(
                    customBackFunction, 101
                );
    
                // cancel custom back behaviour
                var backStateChangeWatcher = $rootScope.$on('$stateChangeStart', function () {
                    if($rootScope.oldSoftBack){
                        deregisterHardBack();
                        deregisterSoftBack();
    
                        // Un-register watcher
                        backStateChangeWatcher();
                    }
                });
            }
        }
    })();
    
    //Called via:
    
        customBackButtonService.setup(function () {
            console.log('custom back');
        });
    

    【讨论】:

      【解决方案3】:

      这是我的解决方案:)

      将这部分代码放在你的 app.js 运行函数中:

      //** Go Back interception function ------------------------------------------
      
          var currentScope;
      
          var defaultGoBack = $rootScope.$ionicGoBack;
      
          $rootScope.$ionicGoBack = function() {
              if ( angular.isFunction( currentScope.customGoBack ) ) {
      
                  //assign default go back function to as a "super" function ^^
                  currentScope.customGoBack.super = defaultGoBack;
      
                  //if there is a custom back function, execute-it
                  currentScope.customGoBack();
      
              } else {
                  //else, execute default go back
                  defaultGoBack();
              }
          };
      
          //Store targetScope to global each time the view is changing
          $rootScope.$on( '$ionicView.beforeEnter', function( event ) {
              currentScope = event.targetScope;
          });
      

      现在,您可以在控制器中创建自定义回退函数:

      $scope.customGoBack = function() {
         console.log( "customGoBack" );
         $scope.customGoBack.super();
      };
      

      当用户点击 nav-back-button 时,将自动调用此函数。

      如果你想自己调用goBack,你可以这样:

      $rootScope.$ionicGoBack();
      

      如果你想在声明的时候绕过自定义函数,你可以这样做:

      $ionicHistory.goBack();
      

      您可以直接在每个控制器中为后退按钮分配不同的行为:)

      【讨论】:

        【解决方案4】:

        我采纳了 Richard 的建议并将其放入服务中以使其更易于重用。

        控制者

        angular.module('MainApp').controller('MyController', ['backButtonOverride'], function (backButtonOverride) {
            // override back button for this controller
            backButtonOverride.setup($scope, function() {
                console.log("custom back");
            });
        }
        

        服务

        angular.module('MainApp.services', []).factory('backButtonOverride', function ($rootScope, $ionicPlatform) {
            var results = {};
        
            function _setup($scope, customBackFunction) {
                // override soft back
                // framework calls $rootScope.$ionicGoBack when soft back button is pressed
                var oldSoftBack = $rootScope.$ionicGoBack;
                $rootScope.$ionicGoBack = function() {
                    customBackFunction();
                };
                var deregisterSoftBack = function() {
                    $rootScope.$ionicGoBack = oldSoftBack;
                };
        
                // override hard back
                // registerBackButtonAction() returns a function which can be used to deregister it
                var deregisterHardBack = $ionicPlatform.registerBackButtonAction(
                    customBackFunction, 101
                );
        
                // cancel custom back behaviour
                $scope.$on('$destroy', function() {
                    deregisterHardBack();
                    deregisterSoftBack();
                });
            }
        
            results.setup = _setup;
            return results;
        });
        

        【讨论】:

        • 这看起来是一种更好的做事方式——我很高兴有真正的 JS 知识的人可以将我的方法更进一步。
        • 谢谢。我不是 JS 方面的专家,但这种方法似乎对我有用。如果有更多 JS 知识的人想重构我的代码,请随意!
        • 谢谢,经过很长时间(几个小时)的反复试验,这种方法似乎效果很好:)
        • @oalbrecht - 我遇到了这个后退按钮覆盖的问题 - 问题是 $scope.$on('$destroy' 似乎没有完全释放覆盖。一旦自定义覆盖加载并且我导航到其他选项卡/页面并使用后退按钮(软和硬)它会将我带回到 customBackFunction() 中定义的位置 - 我不是将我的作为服务使用,而是理查德定义的方式它在上面。更多细节在这里:release override
        • 我已经为使用 TS 的任何人将其移植到 Typescript:gist.github.com/rinogo/1bd363c1b1ce19ef59477b55ea63b474
        【解决方案5】:

        上面覆盖 $rootScope.$ionicGoBack 的答案部分有效。

        问题在于 deregisterSoftBack 的方式。我尝试了上面提到的 $scope.$on('$destroy', a_function) 和新的 $scope.$on('$ionicView.beforeLeave', a_function),都不起作用。

        原因:在deregisterSoftBack之前会进入新的controller,导致deregister失败。所以我稍微修改了解决方案以使其工作。

        1. 改变

          var oldSoftBack = $rootScope.$ionicGoBack
          

          $rootScope.oldSoftBack = $rootScope.$ionicGoBack
          
        2. 在$rootScope.$on("$stateChangeStart", your_function)中注销,代码为:

          if ($rootScope.oldSoftBack) {
              $rootScope.$ionicGoBack = $rootScope.oldSoftBack;
              $rootScope.oldSoftBack = null;
          }
          

        【讨论】:

        • 啊...我想这可能是我的问题。当我导航到其他选项卡并使用那里的后退按钮时,它会将我带回到一个控制器中定义的 customBackButton,该控制器从一开始就覆盖了后退按钮。将发布更新。
        【解决方案6】:

        可以覆盖控制器中的两个按钮,而无需更改 HTML 代码。

        总结一下:

        • 软导航栏按钮 - 覆盖$rootScope.$ionicGoBack()
        • Android 硬按钮 - 使用 $ionicPlatform.registerBackButtonAction()

        下面有详细解释。


        覆盖软导航栏 BACK 按钮的解决方案来自于了解按下该按钮时 Ionic 的作用。

        Ionic docs for ion-nav-back-button,我们已经知道:

        点击/点击按钮会自动设置为$ionicGoBack()

        ionic.bundle.js 中搜索源代码会发现这是如何声明的:

        $rootScope.$ionicGoBack = function(backCount) {
            $ionicHistory.goBack(backCount);
        };
        

        在您自己的控制器中覆盖它很简单。确保将$rootScope 传递到控制器中,然后只修改上面的代码。获取指向原始函数的指针是个好主意,这样您就可以在需要时恢复它,或者在完成自定义处理后调用它。

        // grab pointer to original function
        var oldSoftBack = $rootScope.$ionicGoBack;
        
        // override default behaviour
        $rootScope.$ionicGoBack = function() {
            // do something interesting here
        
            // uncomment below line to call old function when finished
            // oldSoftBack();
        };
        

        覆盖 Android 硬件 BACK 按钮的解决方案,仅适用于一个控制器,来自 registerBackButtonAction() 函数的返回值,该函数会取消注册覆盖。

        $scope.$on('$destroy'... 处理程序中调用该注销方法。

        var doCustomBack= function() {
            // do something interesting here
        };
        
        // registerBackButtonAction() returns a function which can be used to deregister it
        var deregisterHardBack= $ionicPlatform.registerBackButtonAction(
            doCustomBack, 101
        );
        
        $scope.$on('$destroy', function() {
            deregisterHardBack();
        });
        

        更多细节在这里:


        完整的解决方案需要以下内容:

        • 覆盖软导航栏 BACK 按钮
        • 覆盖 Android 硬返回按钮
        • 范围将是单个控制器
        • 恢复默认行为

        以下代码说明了如何做到这一点:

        // run this function when either hard or soft back button is pressed
        var doCustomBack = function() {
            console.log("custom BACK");
        };
        
        // override soft back
        // framework calls $rootScope.$ionicGoBack when soft back button is pressed
        var oldSoftBack = $rootScope.$ionicGoBack;
        $rootScope.$ionicGoBack = function() {
            doCustomBack();
        };
        var deregisterSoftBack = function() {
            $rootScope.$ionicGoBack = oldSoftBack;
        };
        
        // override hard back
        // registerBackButtonAction() returns a function which can be used to deregister it
        var deregisterHardBack = $ionicPlatform.registerBackButtonAction(
            doCustomBack, 101
        );
        
        // cancel custom back behaviour
        $scope.$on('$destroy', function() {
            deregisterHardBack();
            deregisterSoftBack();
        });
        

        这个问题已经在 Ionic 论坛和问题页面上讨论过:

        【讨论】:

        • 这对我们来说非常有效。我们有嵌套的 UI 视图,我们希望后退按钮可以使用。我们最终采用了这种方法,并在子视图的父控制器中使用“window.history.back()”代替了 $ionicGoBack()。尽管 ionic 没有跟踪浏览器的子视图历史堆栈。
        • @koga73 好主意 - 我没想到这样做。
        • @RichardLeMesurier 我怀疑我在堆栈溢出中提出的问题请看一下 [stackoverflow.com/questions/36170488/….
        • 很好的方法,但是在我的自定义返回代码之后我无法调用原始返回函数。解决方案是 oldSoftBack(-1) 在我的自定义返回代码中。
        • @RichardLeMesurier - 我遇到了上述问题。我有 5 个主要选项卡...每个选项卡都指向子选项卡。我将上述内容应用于 TabA_SubTabA 的控制器。我的自定义背面如下:var doCustomBack = function() { $state.transitionTo('tab.A'); } - 它可以工作。但是,如果在 SubTabA 中,我导航到另一个主选项卡 (Tab C),然后单击 TabC-SubTabC 页面之一,则该 SubTabC 上的后退按钮会将我直接带回 TabA。 $scope.$on('$destroy', function() { deregisterSoftBack(); }) 正确恢复了原来的返回功能。
        【解决方案7】:

        您是在谈论 ion-header-bar 或 ion-nav-bar 上的后退按钮中的软导航吗?因为这很容易解决。只需为该模板制作自己的自定义标题栏。所以在那个状态模板上就使用这样的东西。

        <div class="bar bar-header bar-positive">
                <button ng-click="someCustomFunction()" class="button button-clear button-light icon-left ion-chevron-left">Go Back</button>
        </div>
        

        【讨论】:

        • 如果您查看 ionic css 文档,他们会告诉您如何构建一个简单的仅 html 和 css 标题栏,然后您可以在控制器中添加您想要的任何功能,而不是使用 ion -nav-bar 指令。
        • 是的,如果您转到文档,您将在快速导航列表的左侧使用 css。然后它就在 css 文档的顶部。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-01-10
        • 1970-01-01
        • 1970-01-01
        • 2017-01-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多