简体   繁体   English

window.opener.focus() 不起作用

[英]window.opener.focus() doesn't work

I can't seem to get this to work.我似乎无法让它发挥作用。

In response to a click, window A opens window B (which then has focus).响应单击,窗口 A 打开窗口 B(然后具有焦点)。 Then, in response to a click on B, the window calls window.opener.focus() , but the focus does not go back to A.然后,响应第B点击,窗口调用window.opener.focus()但重点回A.

I have found a strange, strange workaround for Chrome (29, possibly others).我发现了一个奇怪的、奇怪的 Chrome 解决方法(29,可能还有其他的)。 If I run:如果我运行:

window.opener.name = 'somename';
window.open(window.opener.location.href, window.opener.name);
window.opener.focus();

it does work (and doesn't reload window A).它确实有效(并且不会重新加载窗口 A)。 But this doesn't work for Firefox, and it is probably a fluke anyway.但这对 Firefox 不起作用,无论如何它可能是侥幸。

It seems very clear to me what opener and focus are supposed to do, but window.opener.focus() doesn't work.我似乎很清楚openerfocus该做什么,但是window.opener.focus()不起作用。 What am I missing?我错过了什么?

From the fine manual : 精美的手册中

Makes a request to bring the window to the front. 发出将窗口移到最前面的请求 It may fail due to user settings and the window isn't guaranteed to be frontmost before this method returns. 由于用户设置,它可能会失败,并且在此方法返回之前,不能保证窗口位于最前面。

Emphasis mine. 强调我的。 Calling focus() is just a request and the browser is free to ignore you and you should generally expect to be ignored. 调用focus()只是一个请求,浏览器可以自由地忽略您,通常应该期望您被忽略。 Consider what sorts of nefarious things you could get up to by switching focus to a tiny window while someone is typing if you need some reasons why a browser would ignore your request. 考虑一下如果有人需要浏览器会忽略您的请求的某些原因,可以在将某人键入时将焦点切换到一个小窗口上,而可能会遇到哪些邪恶的事情。

If you need focus() to work for your application to work then you need to redesign your application so that it doesn't need to call focus() . 如果您需要focus()来使您的应用程序正常工作,那么您需要重新设计应用程序,从而无需调用focus()

I can see why a browser/OS will not allow a child windows to take over the focus (abuse of power). 我可以看到为什么浏览器/ OS不允许子窗口接管焦点(电源滥用)。 Here is a workaround: 这是一种解决方法:

  1. In the parent window, declare a function in "window.external" that will trigger Javascript "alert()" or "confirm()". 在父窗口中,在“ window.external”中声明一个函数,该函数将触发Javascript“ alert()”或“ confirm()”。
  2. Invoke that function from the child window. 从子窗口调用该功能。
  3. The browser might ignore a request from a child window that wants to control the focus (eg window.opener.focus()), but the browser should honor a request from a parent window that triggers an alert() or a confirm() action, which requires to focus on the parent window. 浏览器可能会忽略来自希望控制焦点的子窗口的请求(例如window.opener.focus()),但浏览器应该接受来自父窗口的触发Alert()或Confirm()操作的请求,这需要关注父窗口。

JS Parent: JS家长:

    var child = window.open('child.html', 'child');
    window.external.comeback = function() {
        var back = confirm('Are you sure you want to comback?');
        if(back) {
            child.close();
        } else {
            child.focus();
        }
    }

JS Child: JS Child:

    // assuming you have jQuery
    $('.btn').click() {
        window.opener.external.comeback();  
    };

--I am using this code in a real world application to handle a checkout request that runs in child window, and I need to gracefully return to the parent window. -我在现实世界的应用程序中使用此代码来处理在子窗口中运行的结帐请求,并且需要正常返回到父窗口。

See: SimplifySites.com 请参阅: SimplifySites.com

Web-facing or private intranet? 面向Web还是专用Intranet?

Window management is up to the Browser and the OS. 窗口管理取决于浏览器和操作系统。 HTML & ECMAscript have nothing to say about it. HTML和ECMAscript对此无话可说。

If this is for a public-facing website, then just don't bother -- as they say, "Don't break the web." 如果这是面向面向公众的网站,那么就不要打扰-正如他们所说,“不要破坏网络”。

But I really wanna! 但是我真的很想!

If this is for some tightly managed (say Intranet) application of some kind then you'll need to resort to writing Addons/Extensions. 如果这是针对某种严格管理(例如Intranet)的应用程序,则需要诉诸于编写Addons / Extensions。 It's certaintly easier if you can restrict yourself to a single browser & platform. 如果您可以将自己限制在单个浏览器和平台上,肯定会更容易。

EDIT : Example for Firefox on Win32... 编辑 :Win32上的Firefox示例...

This solution works as a custom addon for Firefox which uses jsctypes internally to load a Win32 DLL. 该解决方案作为Firefox的自定义插件,在内部使用jsctypes加载Win32 DLL。 The window_focus() JavaScript function is exposed which does what you want. window_focus() JavaScript函数,该函数可以执行您想要的操作。

There are 3 parts to this solution: 此解决方案包含3个部分:

  1. The privileged JavaScript code to load/bind the Win32 APIs 特权的JavaScript代码来加载/绑定Win32 API
  2. The CPP header file for our external DLL 我们的外部DLL的CPP头文件
  3. The CPP source file for our external DLL 我们的外部DLL的CPP源文件

I built a simple GUI DLL project in MSVC++ with the later two files & compiled wmctrl.dll , depending on msvcr100.dll , and used Dependency Walker to find the "plain C" symbols exported by the DLL for use by js-ctypes. 我内置的MSVC一个简单的GUI DLL项目++与后来的两个文件和编译wmctrl.dll ,取决于msvcr100.dll ,并用的Dependency Walker来查找DLL文件被JS-ctypes的使用导出的“纯C”标志。 Eg: ?wmctrl_find_window@@YAKPAD@Z is the "plain C" symbol for the C++ api function called wmctrl_find_window . 例如: ?wmctrl_find_window@@YAKPAD@Z是名为wmctrl_find_window的C ++ API函数的“普通C”符号。

As a caveat, this code relies on temporarily being able to change the title of the window that needs to be focused so that Win32 APIs can examine all windows on your desktop to find the correct Firefox window. 需要注意的是,此代码临时依赖于能够更改需要聚焦的窗口的标题,以便Win32 API可以检查桌面上的所有窗口以找到正确的Firefox窗口。

You need to have access to privileged Mozilla platform APIs, ie: JavaScript inside a Firefox Addon. 您需要访问特权的Mozilla平台API,即:Firefox插件中的JavaScript。

In your privileged JavaScript code: 在您的特权JavaScript代码中:

// get API constants (might already be available)
const {Cc,Ci,Cu} = require("chrome");

// import js-ctypes
var file=null, lib=null, ctypes = {};
Cu.import("resource://gre/modules/ctypes.jsm", ctypes);
var ctypes = ctypes.ctypes;

// build platform specific library path
var filename = ctypes.libraryName("wmctrl"); // automatically adds '.dll'
var comp = "@mozilla.org/file/directory_service;1";
var file = Cc[comp].getService(Ci.nsIProperties).get("CurProcD", Ci.nsIFile);
file.append("browser_code"); // or whereever you put your DLL
file.append(filename);

// get the JavaScript library interface (load the library)
var lib = ctypes.open(file.path);

// wmctrl_find_window: returing unsigned 32bit (long) "window handle"
// takes string "window title".
var find_window = lib.declare(
    "?wmctrl_find_window@@YAKPAD@Z",     /* plain "C" DLL symbol  */
    ctypes.stdcall_abi, ctypes.uint32_t, /* return type: uint32   */
    ctypes.char.ptr);                    /* parameter: string     */

// wmctrl_window_focus: takes unsigned 32bit (long) "window handle".
var window_focus = lib.declare(
    "?wmctrl_window_focus@@YAXK@Z",      /* plain "C" DLL symbol  */
    ctypes.stdcall_abi, ctypes.void_t,   /* return type: void     */
    ctypes.uint32_t);                    /* parameter: uint32     */

wmctrldll.h wmctrldll.h

#ifdef WMCTRLDLL_EXPORTS
#define WMCTRLDLL_API __declspec(dllexport)
#else
#define WMCTRLDLL_API __declspec(dllimport)
#endif

WMCTRLDLL_API void wmctrl_window_focus (unsigned long wid);
WMCTRLDLL_API unsigned long wmctrl_find_window(char* find_title);

wmctrldll.cpp wmctrldll.cpp

typedef struct {
  HWND hWnd;
  char title[255];
} myWinSpec;

BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam) {
  char String[255];
  myWinSpec* to_find = (myWinSpec*) lParam;

  // not a window
  if (!hWnd) return TRUE;                                   

  // not visible
  if (!IsWindowVisible(hWnd)) return TRUE;

  // no window title                  
  if (!GetWindowTextA(hWnd, (LPSTR)String, 255)) return TRUE;

  // no title match
  if (strcmp(String, to_find->title) != 0) return TRUE;     

  to_find->hWnd = hWnd;
  return FALSE;
}

WMCTRLDLL_API void wmctrl_window_focus(unsigned long wid) {
  SetForegroundWindow((HWND) wid);
}

WMCTRLDLL_API unsigned long wmctrl_find_window(char* find_title) {
  myWinSpec to_find;

  sprintf_s(to_find.title, sizeof(to_find.title), "%s", find_title);
  to_find.hWnd = 0;

  EnumWindows(EnumWindowsProc, (LPARAM)&to_find);
  return (unsigned long) to_find.hWnd;
}

Workaround In main window added script function: 解决方法在主窗口中添加脚本功能:

    function here() {
        alert('Welcome Back')  // seems needed to wake up document
        window.focus()
    }

In opened window invoke script function: 在打开的窗口中调用脚本函数:

    function HomeTab()  {
        O = window.opener;
        if (O)
            if (O.closed)   alert('Home page has been closed')
            else    O.here()
        else alert('This tab has no home page')
    }

Works widely differently in different browsers Some will have the parent tab blink Some mark the parent tab, and you have to notice it Some you have to click on home tab the first time and you can then give it permission to go directly to home tab without a confirm box. 在不同的浏览器中的工作方式大不相同。有些会使其父选项卡闪烁一些会标记父选项卡,您必须注意到它有些您必须第一次单击主页选项卡,然后才可以授予它直接进入主页选项卡的权限,而无需确认框。

I found a reasonable workaround for this using web Notifications .我使用 web Notifications找到了一个合理的解决方法。

As mentioned in some of the other answers here there are some constraints with browsers and the OS where window.opener.focus() may not work.正如这里的其他一些答案中提到的,浏览器和操作系统存在一些限制,window.opener.focus() 可能无法正常工作。

I was able to get this to work using postMessage and Notifications.我能够使用 postMessage 和 Notifications 让它工作。

To try this out: From the parent (opener) tab add a 'message' event listener that creates a notification with a click listener:试试这个:从父(打开器)选项卡添加一个“消息”事件侦听器,它创建一个带有点击侦听器的通知:

 window.addEventListener("message", (event) => {
  if (!("Notification" in window)) {
    alert("This browser does not support desktop notification");
  }

  // Let's check whether notification permissions have already been granted
  else if (Notification.permission === "granted") {
    // If it's okay let's create a notification
    var notification = new Notification("The opener needs your attention");

    // Add click listener that will perform a window focus
    notification.onclick = function (x) {
      window.focus();
      this.close();
    };
  }

  // Otherwise, we need to ask the user for permission
  else if (Notification.permission !== "denied") {
    Notification.requestPermission().then(function (permission) {
      // If the user accepts, let's create a notification
      if (permission === "granted") {
        var notification = new Notification("The opener needs your attention");

        // Add click listener that will perform a window focus
        notification.onclick = function (x) {
          window.focus();
          this.close();
        };
      }
    });
  }
});

Then from the child tab you need to use postMessage when focus back to parent tab is needed:然后从子选项卡中,当需要将焦点返回到父选项卡时,您需要使用 postMessage:

// Called from child tab
window.opener.postMessage(
  {
    message: "focus",
  },
  "*" // cross-origin
);

Once you call postMessage you should see a OS Web notification.调用 postMessage 后,您应该会看到操作系统 Web 通知。 If a user clicks this they should be redirected to the parent (opener) tab.如果用户点击它,他们应该被重定向到父(开启者)选项卡。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM