【问题标题】:AngularJS: How to open a file in a new tab?AngularJS:如何在新选项卡中打开文件?
【发布时间】:2014-07-11 00:46:18
【问题描述】:

LIVE DEMO

给定一个文件的 URI,我想在新标签页(不是新窗口)中打开它。

It looks like 不可能使用$window.open(uri, '_blank')

所以,我尝试了以下技巧:

var link = angular.element('<a href="uri-here" target="_blank"></a>');
angular.element(document.body).append(link);
link[0].click();
link.remove();

it works

但是,如果我将完全相同的代码放入 promise 回调中,它就不再起作用(而是在新窗口中打开文件)。

知道这里发生了什么吗?

PLAYGROUND HERE

【问题讨论】:

  • 无法做到。新页面是在窗口中打开还是在新标签中打开是用户偏好,并且无法更改。
  • 您的演示游乐场似乎按预期工作。我在 IE 11 上。
  • @pixelbits 有趣。它似乎也适用于 Firefox 30.0。我想知道为什么它在 Chrome 中不起作用(在我的例子中是 35.0)。
  • 正如其他人指出的那样,您不能覆盖用户对浏览器行为的选择(甚至是默认行为)。无论如何,我会用更干净(和可读)$window.open('http://martinfowler.com/ieeeSoftware/whenType.pdf') 重写链接的“肮脏技巧”
  • 简单的答案是安全说你不能。我认为维护选项卡的最佳方法是将文件选择逻辑简单地移动到为新窗口提供服务的内容中并放弃 ajax 调用,无论如何这是一个毫无意义的步骤,不是吗。

标签: javascript angularjs


【解决方案1】:

根据您的代码/内容,您不能强制浏览器打开一个新标签(而不是一个新窗口,反之亦然)。以一种或另一种方式强制它取决于浏览器设置。

其他任何事情都会有安全风险。

【讨论】:

  • 您能否解释一下为什么这会带来安全风险?为什么你认为在新标签页中打开是 Firefox 和 IE 的默认行为,而不是 Chrome?
  • 这是关于能够吸引(或逃避)最终用户的注意力。浏览器对如何打开新窗口(功能实际执行的操作)以及是否改为/可选地在新选项卡下的同一窗口中打开它们具有默认策略。用户习惯于浏览器提供的任何策略。浏览器为最终用户(而非网站)提供了覆盖默认策略的方法。通过能够以一种或另一种方式强制它,您将获得让您的新内容被一些用户忽视和/或惹恼其他已经表达了他们的偏好的用户的能力。跨度>
【解决方案2】:

让我们了解弹出窗口阻止程序的基本工作原理。

如果用户触发该功能打开一个新的 url,那么弹出窗口拦截器将允许它(它应该适用于任何现代浏览器 - 至少是 firefox、chrome)

如果不是来自用户(例如后台的 javascript 函数、promise 或任何其他非来自用户的函数触发),浏览器将阻止,除非用户手动将站点列入白名单。

这不起作用。

function openInNewTab() {
    window.open('http://stackoverflow.com','_blank');
}

openInNewTab();//fail

这是有效的

<h1><button onclick="openInNewTab()">Open In New Tab - working</button></h1>

我创建了简单的 plunkr 版本 - http://plnkr.co/edit/QqsEzMtG5oawZsQq0XBV?p=preview

所以,回答你的问题。除非用户授权(用户触发它或将站点列入白名单),否则这是不可能的。

来自火狐的引述——

弹出窗口或弹出窗口是自动出现的窗口 未经您的许可。

https://support.mozilla.org/en-US/kb/pop-blocker-settings-exceptions-troubleshooting

*在新标签页/新窗口中打开没有任何区别。弹出窗口阻止程序仍将始终阻止。这并不意味着如果在新标签页中打开浏览器将允许。巧合的是,某些浏览器默认以这种方式设置。

解决方法

您可以明确要求用户在后台执行后触发在新选项卡中打开的功能。
您可以在 UI 中显示消息以要求用户打开 url。 示例 - http://plnkr.co/edit/iyNzpg64DtsrijAGbHlT?p=preview

【讨论】:

    【解决方案3】:

    您只能在 由用户触发click 事件处理程序中打开新窗口。

    原因是可用性

    我不确定是否所有浏览器都有这种行为,但有些浏览器不允许脚本在在用户不被注意的情况下打开窗口。想象一下,当您访问一个网页时,突然,该网页打开了几个窗口 => 很烦人。

    看到这个DEMO(用我的Chrome和Firefox测试过),即使我们通过脚本触发点击事件,浏览器仍然会阻止弹出窗口。

    $("#test").click(function(){
        openInNewTab();
    });
    
    $("#test").click();
    

    您无法在 ajax 成功回调中打开新窗口,因为您的 ajax 成功在 click 事件处理程序完成其执行后在另一个循环中运行。

    请参阅此link 了解解决方法

    如果我将完全相同的代码放在一个 promise 回调中,它就不起作用 不再(它会在新窗口中打开文件)。

    我很惊讶您仍然能够打开一个新窗口。但是这个问题确实和用户触发的点击事件有很大关系。

    【讨论】:

    • 顺便说一句,您的链接 jsbin.com/cuhekeve/1/edit 在我的浏览器(Chrome 和 Firefox)中被阻止,因为它不在用户触发的点击事件处理程序中。
    【解决方案4】:

    您的问题有两个方面,而且两个方面都涉及不确定的领域。


    在过去的浏览器时代,window.open 就是这样做的——打开一个新窗口。那是因为标签的概念还没有被发明出来。当标签被引入时,它们被完全视为窗口以提高兼容性,并且这种传统一直持续到今天。那,以及 window.open 只是 standardized very recently 的事实意味着 JavaScript 无法区分窗口和选项卡。

    没有“正常”的方式来指定链接是否应在新标签页中打开。不过,您可以使用以下技巧:为 open 调用指定自定义窗口大小(通过第三个参数),如下所示:

    window.open('http://example.com', '', 'width=' + screen.width);
    

    这将导致几乎所有浏览器都打开一个单独的窗口,因为选项卡不能具有自定义大小。


    在 JavaScript 中,有 trusted 事件和 untrusted 事件。例如,受信任的事件是用户对链接的合法点击,而不受信任的事件是对链接的手动click() 调用。

    只有受信任的事件处理程序才能打开新窗口/选项卡。这是为了防止客户端攻击导致浏览器崩溃或通过在mouseover 或类似内容上快速打开一百个标签来迷惑用户。

    您的第二个示例不起作用,因为弹出窗口阻止程序阻止了您通过 click() 触发的不受信任的事件。虽然它是由真正的点击引起的,但中间的异步调用切断了信任的链接。

    【讨论】:

      【解决方案5】:

      working version

      $http.get('https://api.github.com/users/angular').then(openInNewTab());
      

      编辑----------------

      不知道为什么,但是从回调函数调用的 click() 方法与直接调用它的行为不同。

      您可以在此处查看设置间隔示例。

      这就是为什么我直接调用函数而不是通过回调。

      see it with timer callback

      【讨论】:

      • 我建议使用 .success(),如果遇到失败条件,您可以更改结果。然而,这不是问题。问题是他们想要覆盖浏览器功能:“在新选项卡中(不是新窗口)”
      • 知道为什么.then(openInNewTab()) 有效但.then(openInNewTab) 无效吗?
      • .then 需要一个函数。当调用 openInNewTab() 时,它的返回值被传递给“then”。但是 openInNewTab 没有返回任何东西——它是未定义的。我怀疑它可能由于错误的原因而起作用。
      • .then(openInNewTab()) 有效,因为openInNewTab() 被立即调用,相当于演示中的第一个工作按钮。问题是,如果在回调中调用 later,为什么它不起作用。这个答案并没有真正回答问题。
      • @Misha Moroshko,请参阅我回答中的第二个示例。回调中的点击函数行为不同。它不是棱角分明的。这是浏览器的事情。不知道具体原因。
      【解决方案6】:

      或者你可以使用 $window 服务请看这里:http://plnkr.co/edit/8egebfFj4T3LwM0Kd64s?p=preview

      angular.module("Demo", []).controller("DemoCtrl", function($scope, $http, $window) {
        $scope.uri = 'http://martinfowler.com/ieeeSoftware/whenType.pdf';
      
        function openInNewTab() {
      
          var link = angular.element('<a href="' + $scope.uri + '" target="_blank"></a>');
      
          angular.element(document.body).append(link);
      
          link[0].click();
          link.remove();
        }
      
        $scope.works = openInNewTab;
      
        $scope.doesntWork = function() {
          $http.get('https://api.github.com/users/angular').then($window.open($scope.uri));
        };
      });
      

      【讨论】:

      • 这个$window.open($scope.uri)运行immediately,返回值被传递给.then。这就是它起作用的原因。
      【解决方案7】:

      对我们来说,以下方法效果很好:http://blog-it.hypoport.de/2014/08/19/how-to-open-async-calls-in-a-new-tab-instead-of-new-window-within-an-angularjs-app/

      简而言之:我们会记住对新窗口的引用并在之后更改位置。

      【讨论】:

        猜你喜欢
        • 2017-09-28
        • 2015-04-19
        • 1970-01-01
        • 1970-01-01
        • 2019-04-12
        • 2014-06-24
        • 1970-01-01
        • 2017-02-01
        • 2016-10-12
        相关资源
        最近更新 更多