IE8——focus函数不好用

这个问题在日本的msdb论坛上(下面的URL)也有讨论,并且有了一定的结论,现在把结果转过来。
http://social.msdn.microsoft.com/Forums/ja-JP/internetexplorerja/thread/3a7e083c-c75c-4cac-ad23-a733ede6e04c

首先是这一现象的原因的简单分析。

从下面的url来看,微软宣称,从ie8开始,focus函数不再把激活的窗口带到最前面,而仅仅使之在任务栏闪烁。
http://msdn.microsoft.com/ja-jp/library/ms536425(en-us,VS.85).aspx
可从实际的测试中来看,在有些环境下,focus仍然有时候会成功( 成功:会把窗口带到最前面,失败:仅仅在任务栏闪烁)。
进一步的调查发现,
在系统参数 FOREGROUNDLOCKTIMEOUT设置为0时,focus的表现为有时成功,有时失败,
而当 FOREGROUNDLOCKTIMEOUT设置为200000时(系统的初始值),focus的表现为 完全失败。

根据推测,focus也应该是使用了SetForegroundWindow的方法来将窗口带到最前面(Z-order的顶端,前景窗口)。
由于ie8使用了LCIE的进程分离技术,父窗口和子窗口不再处于一个进程。当父窗口处于最前方的时候,
子窗口所属进程就不再是foreground。从而导致使SetForegroundWindow成功需要的前提条件,不再符合。

所以这一现象,更有可能是由于LCIE导致的边缘效果。

FOREGROUNDLOCKTIMEOUT: 
http://msdn.microsoft.com/en-us/library/ms724947(VS.85).aspx
SetForegroundWindow: 
http://msdn.microsoft.com/en-us/library/ms633539(VS.85).aspx

这一现象有以下的回避或者解决手段。

1 LCIE无效(TabProcGrowth=1)
这样,父窗口和子窗口处于一个进程,focus就总能成功。
不过,一是要修改注册表,二是不能再享受LCIE带来的好处。

FOREGROUNDLOCKTIMEOUT设为0,连续调用focus(比如说,用一个100回的循环)
使用javascript和activeX修改FOREGROUNDLOCKTIMEOUT的方法如下(需要有安装Excel):
将下面的命令敲入ie的地址栏,回车即可。
TIMEOUT=0(focus有时成功,有时失败)
javascript:alert( (new ActiveXObject("Excel.Application")).ExecuteExcel4Macro('CALL("user32","SystemParametersInfoA","JJJJJ",8193,0,0,0)')?"设定完了!":"" );
TIMEOUT=200000(系统的初始值)
javascript:alert( (new ActiveXObject("Excel.Application")).ExecuteExcel4Macro('CALL("user32","SystemParametersInfoA","JJJJJ",8193,0,200000,0)')?"设定完了!":"" );
事实上,由于很多软件在安装的时候都会改变 FOREGROUNDLOCKTIMEOUT。参照上面的SetForegroundWindow的url。

3 如果不想改变系统设定的话,可以使用WScript.Shell这个Activex控件。使用WScript.Shell的 AppActivate方法。
Option Explicit
Dim win
Sub Activate
win.focus
win.document.focus
If win.document.hasFocus() Then Exit Sub
Dim wShell
Set wShell=CreateObject("WScript.Shell")
If wShell.AppActivate(win.document.title) Then Exit Sub
Dim LocationURL
LocationURL=win.location.href
If Left(LocationURL,8)="file:///" Then LocationURL=Replace(UnEscape(Mid(LocationURL,9)),"/","/")
If LocationURL="about:blank" Then LocationURL="空白页"
If wShell.AppActivate(LocationURL) Then Exit Sub
End Sub
更复杂的版本,请参照下面的url。
http://scripting.cocolog-nifty.com/blog/2009/08/ie7ie8windowope.html

4 如果Activex控件也不想利用的话,可以用下面的方法。
不过这个方法,会弹出【focus moving...】的警告窗口。
Sub MsgActivate
win.focus
win.document.focus
If win.document.hasFocus() Then Exit Sub
win.setTimeout "MsgBox ""focus moving..."",vbSystemModal",0,"vbscript"
End Sub

下面是一个完整的例子。
<html>
<head>
<title>opener</title>
<object id=wShell classid=clsid:72C24DD5-D70A-438B-8A42-98424B88AFB8></object>
<script language=vbscript>
Option Explicit
Dim win
Sub Activate(win)
win.focus
win.document.focus
If win.document.hasFocus() Then Exit Sub
Dim wShell
Set wShell=CreateObject("WScript.Shell")
If wShell.AppActivate(win.document.title) Then Exit Sub
Dim LocationURL
LocationURL=win.location.href
If Left(LocationURL,8)="file:///" Then LocationURL=Replace(UnEscape(Mid(LocationURL,9)),"/","/")
If LocationURL="about:blank" Then LocationURL="空白のページ"
If wShell.AppActivate(LocationURL) Then Exit Sub
End Sub

Sub MsgActivate(win)
win.focus
win.document.focus
If win.document.hasFocus() Then Exit Sub
win.setTimeout "MsgBox ""focus moving..."",vbSystemModal",0,"vbscript"
End Sub
</script>
<script language="javascript" type="text/javascript">
<!--
	var newWin = null;
	var myurl = 'child.htm';
	function OpenNewWindow() 
	{
		newWin = window.open('child.htm','popup','width=550, height=262, toolbar=0, resizable=false');
	}
	function FocusNewWindowByActivate(){
		if (newWin != null && !newWin.closed){
			Activate(newWin);
		}
	}
	function FocusNewWindowByFocus(){
		if (newWin != null && !newWin.closed){
			newWin.focus();
		}
	}
	
	function FocusNewWindowByMsgActivate(){
		if (newWin != null && !newWin.closed){
			MsgActivate(newWin);
		}
	}
	
-->
</script>
</head>
<body>
<button onclick='OpenNewWindow()'>open child.htm in window</button>
<button onclick="FocusNewWindowByFocus()">FocusNewWindowByFocus</button>
<button onclick="FocusNewWindowByActivate()">FocusNewWindowByActivate</button>
<button onclick="FocusNewWindowByMsgActivate()">FocusNewWindowByMsgActivate</button>

</body>
</html>

最后,有关这个现象还有一些没有解决的问题。除了上面提到的之外,focus的表现似乎还和其他条件有关。
不过暂时就先到这儿了。也许以后的ie会修正这个问题。

希望能对遇到类似问题的朋友有所帮助,祝大家愉快。



  • 已标记为答案hatzhang 2009年8月20日 7:26

全部回复

  • 2009年8月20日 7:26 hatzhang 用户奖牌用户奖牌用户奖牌用户奖牌用户奖牌
      已答复 包含代码
    登录进行投票
    0
    登录进行投票
    这个问题在日本的msdb论坛上(下面的URL)也有讨论,并且有了一定的结论,现在把结果转过来。
    http://social.msdn.microsoft.com/Forums/ja-JP/internetexplorerja/thread/3a7e083c-c75c-4cac-ad23-a733ede6e04c

    首先是这一现象的原因的简单分析。

    从下面的url来看,微软宣称,从ie8开始,focus函数不再把激活的窗口带到最前面,而仅仅使之在任务栏闪烁。
    http://msdn.microsoft.com/ja-jp/library/ms536425(en-us,VS.85).aspx
    可从实际的测试中来看,在有些环境下,focus仍然有时候会成功( 成功:会把窗口带到最前面,失败:仅仅在任务栏闪烁)。
    进一步的调查发现,
    在系统参数 FOREGROUNDLOCKTIMEOUT设置为0时,focus的表现为有时成功,有时失败,
    而当 FOREGROUNDLOCKTIMEOUT设置为200000时(系统的初始值),focus的表现为 完全失败。

    根据推测,focus也应该是使用了SetForegroundWindow的方法来将窗口带到最前面(Z-order的顶端,前景窗口)。
    由于ie8使用了LCIE的进程分离技术,父窗口和子窗口不再处于一个进程。当父窗口处于最前方的时候,
    子窗口所属进程就不再是foreground。从而导致使SetForegroundWindow成功需要的前提条件,不再符合。

    所以这一现象,更有可能是由于LCIE导致的边缘效果。

    FOREGROUNDLOCKTIMEOUT: 
    http://msdn.microsoft.com/en-us/library/ms724947(VS.85).aspx
    SetForegroundWindow: 
    http://msdn.microsoft.com/en-us/library/ms633539(VS.85).aspx

    这一现象有以下的回避或者解决手段。

    1 LCIE无效(TabProcGrowth=1)
    这样,父窗口和子窗口处于一个进程,focus就总能成功。
    不过,一是要修改注册表,二是不能再享受LCIE带来的好处。

    FOREGROUNDLOCKTIMEOUT设为0,连续调用focus(比如说,用一个100回的循环)
    使用javascript和activeX修改FOREGROUNDLOCKTIMEOUT的方法如下(需要有安装Excel):
    将下面的命令敲入ie的地址栏,回车即可。
    TIMEOUT=0(focus有时成功,有时失败)
    javascript:alert( (new ActiveXObject("Excel.Application")).ExecuteExcel4Macro('CALL("user32","SystemParametersInfoA","JJJJJ",8193,0,0,0)')?"设定完了!":"" );
    TIMEOUT=200000(系统的初始值)
    javascript:alert( (new ActiveXObject("Excel.Application")).ExecuteExcel4Macro('CALL("user32","SystemParametersInfoA","JJJJJ",8193,0,200000,0)')?"设定完了!":"" );
    事实上,由于很多软件在安装的时候都会改变 FOREGROUNDLOCKTIMEOUT。参照上面的SetForegroundWindow的url。

    3 如果不想改变系统设定的话,可以使用WScript.Shell这个Activex控件。使用WScript.Shell的 AppActivate方法。
    Option Explicit
    Dim win
    Sub Activate
    win.focus
    win.document.focus
    If win.document.hasFocus() Then Exit Sub
    Dim wShell
    Set wShell=CreateObject("WScript.Shell")
    If wShell.AppActivate(win.document.title) Then Exit Sub
    Dim LocationURL
    LocationURL=win.location.href
    If Left(LocationURL,8)="file:///" Then LocationURL=Replace(UnEscape(Mid(LocationURL,9)),"/","/")
    If LocationURL="about:blank" Then LocationURL="空白页"
    If wShell.AppActivate(LocationURL) Then Exit Sub
    End Sub
    
    更复杂的版本,请参照下面的url。
    http://scripting.cocolog-nifty.com/blog/2009/08/ie7ie8windowope.html

    4 如果Activex控件也不想利用的话,可以用下面的方法。
    不过这个方法,会弹出【focus moving...】的警告窗口。
    Sub MsgActivate
    win.focus
    win.document.focus
    If win.document.hasFocus() Then Exit Sub
    win.setTimeout "MsgBox ""focus moving..."",vbSystemModal",0,"vbscript"
    End Sub
    

    下面是一个完整的例子。
    <html>
    <head>
    <title>opener</title>
    <object id=wShell classid=clsid:72C24DD5-D70A-438B-8A42-98424B88AFB8></object>
    <script language=vbscript>
    Option Explicit
    Dim win
    Sub Activate(win)
    win.focus
    win.document.focus
    If win.document.hasFocus() Then Exit Sub
    Dim wShell
    Set wShell=CreateObject("WScript.Shell")
    If wShell.AppActivate(win.document.title) Then Exit Sub
    Dim LocationURL
    LocationURL=win.location.href
    If Left(LocationURL,8)="file:///" Then LocationURL=Replace(UnEscape(Mid(LocationURL,9)),"/","/")
    If LocationURL="about:blank" Then LocationURL="空白のページ"
    If wShell.AppActivate(LocationURL) Then Exit Sub
    End Sub
    
    Sub MsgActivate(win)
    win.focus
    win.document.focus
    If win.document.hasFocus() Then Exit Sub
    win.setTimeout "MsgBox ""focus moving..."",vbSystemModal",0,"vbscript"
    End Sub
    </script>
    <script language="javascript" type="text/javascript">
    <!--
    	var newWin = null;
    	var myurl = 'child.htm';
    	function OpenNewWindow() 
    	{
    		newWin = window.open('child.htm','popup','width=550, height=262, toolbar=0, resizable=false');
    	}
    	function FocusNewWindowByActivate(){
    		if (newWin != null && !newWin.closed){
    			Activate(newWin);
    		}
    	}
    	function FocusNewWindowByFocus(){
    		if (newWin != null && !newWin.closed){
    			newWin.focus();
    		}
    	}
    	
    	function FocusNewWindowByMsgActivate(){
    		if (newWin != null && !newWin.closed){
    			MsgActivate(newWin);
    		}
    	}
    	
    -->
    </script>
    </head>
    <body>
    <button onclick='OpenNewWindow()'>open child.htm in window</button>
    <button onclick="FocusNewWindowByFocus()">FocusNewWindowByFocus</button>
    <button onclick="FocusNewWindowByActivate()">FocusNewWindowByActivate</button>
    <button onclick="FocusNewWindowByMsgActivate()">FocusNewWindowByMsgActivate</button>
    
    </body>
    </html>
    

    最后,有关这个现象还有一些没有解决的问题。除了上面提到的之外,focus的表现似乎还和其他条件有关。
    不过暂时就先到这儿了。也许以后的ie会修正这个问题。

    希望能对遇到类似问题的朋友有所帮助,祝大家愉快。

你可能感兴趣的:(JavaScript,function,IE,null,url,VBScript)