13

我似乎无法让它工作。

响应单击,窗口 A 打开窗口 B(然后具有焦点)。然后,响应单击 B,窗口调用window.opener.focus(),但焦点不会回到A。

我为 Chrome 找到了一个奇怪的解决方法(29,可能还有其他)。如果我运行:

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

它确实有效(并且不会重新加载窗口 A)。但这对 Firefox 不起作用,而且这可能是侥幸。

我似乎很清楚应该做什么和opener该做什么,但不起作用。我错过了什么?focuswindow.opener.focus()

4

5 回答 5

9

来自精美手册

请求将窗口置于前面它可能由于用户设置而失败,并且在此方法返回之前不能保证窗口位于最前面。

强调我的。调用focus()只是一个请求,浏览器可以随意忽略您,您通常应该期望被忽略。如果您需要一些浏览器会忽略您的请求的原因,请考虑通过在有人打字时将焦点切换到一个小窗口来解决什么样的邪恶事情。

如果您需要focus()为您的应用程序工作,那么您需要重新设计您的应用程序,以便它不需要调用focus().

于 2013-08-29T02:17:03.110 回答
2

我可以看到为什么浏览器/操作系统不允许子窗口接管焦点(滥用权力)。这是一种解决方法:

  1. 在父窗口中,在“window.external”中声明一个将触发Javascript“alert()”或“confirm()”的函数。
  2. 从子窗口调用该函数。
  3. 浏览器可能会忽略来自想要控制焦点的子窗口的请求(例如 window.opener.focus()),但浏览器应该接受来自触发 alert() 或 confirm() 操作的父窗口的请求,这需要关注父窗口。

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 孩子:

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

--我在现实世界的应用程序中使用此代码来处理在子窗口中运行的结帐请求,我需要优雅地返回到父窗口。

于 2016-01-05T07:37:19.363 回答
1

面向 Web 还是私有 Intranet?

窗口管理取决于浏览器和操作系统。HTML 和 ECMAscript 对此无话可说。

如果这是针对面向公众的网站,那么请不要打扰 - 正如他们所说,“不要破坏网络”。

但我真的很想!

如果这是针对某种严格管理(例如 Intranet)的应用程序,那么您将需要求助于编写插件/扩展。如果您可以将自己限制在单个浏览器和平台上,那肯定会更容易。

编辑:Win32 上的 Firefox 示例...

此解决方案用作 Firefox 的自定义插件,它在jsctypes内部使用加载 Win32 DLL。JavaScript 函数已公开,window_focus()可以执行您想要的操作。

此解决方案有 3 个部分:

  1. 用于加载/绑定 Win32 API 的特权 JavaScript 代码
  2. 我们外部 DLL 的 CPP 头文件
  3. 我们外部 DLL 的 CPP 源文件

我在 MSVC++ 中构建了一个简单的 GUI DLL 项目,其中包含后两个文件并编译wmctrl.dll,具体取决于msvcr100.dll,并使用Dependency Walker查找 DLL 导出的“普通 C”符号以供 js-ctypes 使用。例如:?wmctrl_find_window@@YAKPAD@Z是 C++ api 函数的“普通 C”符号,称为wmctrl_find_window.

需要注意的是,此代码依赖于临时能够更改需要聚焦的窗口的标题,以便 Win32 API 可以检查桌面上的所有窗口以找到正确的 Firefox 窗口。

您需要访问特权 Mozilla 平台 API,即:Firefox 插件中的 JavaScript。

在您的特权 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

#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

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;
}
于 2013-08-29T02:25:23.237 回答
0

我使用 web Notifications找到了一个合理的解决方法。

正如在此处的其他一些答案中所提到的,浏览器和操作系统存在一些限制,其中 window.opener.focus() 可能无法正常工作。

我能够使用 postMessage 和 Notifications 让它工作。

尝试一下:从父(打开器)选项卡添加一个“消息”事件侦听器,该侦听器创建一个带有点击侦听器的通知:

 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();
        };
      }
    });
  }
});

然后,当需要将焦点返回到父选项卡时,您需要从子选项卡使用 postMessage :

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

调用 postMessage 后,您应该会看到 OS Web 通知。如果用户点击它,他们应该被重定向到父(开启者)选项卡。

于 2021-11-16T19:07:43.467 回答
-1

解决方法在主窗口中添加脚本功能:

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

在打开的窗口调用脚本函数:

    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')
    }

在不同的浏览器中工作方式不同 有些会使父选项卡闪烁 有些标记父选项卡,你必须注意它 有些你必须第一次单击主页选项卡,然后你可以授予它直接进入主页选项卡的权限,而无需一个确认框。

于 2019-04-04T04:36:12.413 回答