我该如何让ui-router跳转到外部链接,比如google.com?

26

例如:

 $stateProvider
            .state('external', {
                url: 'http://www.google.com',

            })

网址假定这是一个内部状态。我希望它像href或类似的东西。

我有一个导航结构,将从UI路由构建,并且我需要一个链接到外部链接的链接。 不一定只是谷歌,那只是个例子。

不希望在链接中找到它,也不希望使用$state.href('http://www.google.com')。 需要在路由配置中声明性地使用它。


我不确定是否存在更简单的方法 - 可能有。但您考虑过一种折中方案吗?在您的 $route 对象中加入一个键(例如 externalURL),一个函数,当键/值存在时将浏览器重定向,并且仅在配置或运行阶段期间绑定 $on("$routeChangeStart", redirectIfExternal) - DRobinson
5个回答

38

Angular-ui-router 不支持外部 URL,你需要使用 $location.url() 或者 $window.open() 来重定向用户。

我建议您使用 $window.open('http://www.google.com', '_self') ,它将在同一页上打开 URL。

更新

您还可以通过添加参数 external 自定义 ui-router,它可以是 true/false

  $stateProvider
  .state('external', {
       url: 'http://www.google.com',
       external: true
  })

然后在您的状态中配置$stateChangeStart并处理重定向部分。

运行块

myapp.run(function($rootScope, $window) {
  $rootScope.$on('$stateChangeStart',
    function(event, toState, toParams, fromState, fromParams) {
      if (toState.external) {
        event.preventDefault();
        $window.open(toState.url, '_self');
      }
    });
})

示例 Plunkr

注意: 为了使其正常工作,请在新窗口中打开 Plunkr,因为由于某些安全原因,谷歌 在 iFrame 中无法打开。


有趣。我希望有一个 external: true 的配置参数或者类似的东西。 - Shane
3
Angular 不希望你离开 :P - HankScorpio
只是一个玩笑。Angular并不想让你离开,他们希望你留在网页上,所以他们没有像Shane想要的那样提供一个简单的配置参数。 - HankScorpio
嗯...有趣。让我试试看。 - Shane
3
+1 这是正确的做法。你应该尽可能避免与现有属性“url”混合,而是使用类似“externalUrl”的名称,以避免混淆并保留“url”功能(当然不再需要“external”标志)。 - rixo
显示剩余3条评论

27
你可以使用onEnter回调函数:
 $stateProvider
    .state('external', {
        onEnter: function($window) {
            $window.open('http://www.google.com', '_self');
        }
    });

编辑

在pankajparkar的回答基础上,我认为您应该避免覆盖现有的参数名称。ui-router花费了大量精力来区分状态和URL,因此同时使用urlexternalUrl可能是有意义的...

因此,我会这样实现一个externalUrl参数:

myApp.run(function($rootScope, $window) {
    $rootScope.$on(
        '$stateChangeStart',
        function(event, toState, toParams, fromState, fromParams) {
            if (toState.externalUrl) {
                event.preventDefault();
                $window.open(toState.externalUrl, '_self');
            }
        }
    );
});

使用方法如下,可以带有或不带内部URL:

$stateProvider.state('external', {
    // option url for sref
    // url: '/to-google',
    externalUrl: 'http://www.google.com'
});

1
请使用 $location.url() 替代。 - HankScorpio
当然,最好使用Angular的实用工具而不是裸的JavaScript。 $location.url 在这种情况下似乎不起作用,所以还要感谢@pankajparkar提供的其余解决方案。 - rixo
这不行吗?这很惊奇...你刚测试过了吗? - HankScorpio
1
@HankScorpio $location 用于应用程序状态之间的导航,不适用于访问外部网站 - rixo
1
你也可以使用 $window.location.href 或者原生的 JS window.location.href / window.location.replace。 - hogan
@KishorK(和hogan)是的,纯JS当然可以工作,但我们的重点是使用Angular包装器来遵循最佳实践(主要目的是允许在测试中轻松进行模拟,但这是另一个问题)。 - rixo

11

OnEnter解决方案可能是最干净的,而且它可以防止$rootScope上的监听器一直被触发。我不太明白为什么"$window"可以在没有注入的情况下使用--它似乎只是起作用了。 - pinnprophead
@pinnprophead 我认为这更简单,当我想要排除某些链接参与angular路由时,这是我的观点。 为了进行这种排序,我需要添加一个函数来单独决定该链接的排除方式。 但是当我使用target="_self"时,它会排除我们想要的那些链接的深度链接。 我希望这可以帮助到您。 - Ebrahim

1
我将接受的答案改写成了一个假设最新版本的AngularJS(目前是1.6)、ui-router 1.x、使用Babel转译的Webpack 2和Babel的ng-annotate插件的答案。
.run(($transitions, $window) => {
  'ngInject'
  $transitions.onStart({
    to: (state) => state.external === true && state.url
  }, ($transition) => {
    const to = $transition.to()
    $window.open(to.url, to.target || '_self')
    return false
  })
})

这里是状态可能被配置的方式:
.config(($stateProvider) => {
  'ngInject'
  $stateProvider
    .state({
      name: 'there',
      url:'https://google.com',
      external: true,
      target: '_blank'
    })
})

使用方法:

<a ui-sref="there">To Google</a>

1
原始答案在UI Router中已经弃用并且默认禁用,您可以尝试使用转换钩子来实现它。
  .state("mystate", {
    externalUrl: 'https://google.com'
  })

然后:
myApp.run(['$transitions', '$window', ($transitions, $window) => {
  $transitions.onEnter({}, function (transition) {
    const toState = transition.to();

    if (toState.externalUrl) {
      $window.open(toState.externalUrl, '_self');
      return false;
    }
    return true;
  });
}]
);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接