4.内嵌 IE 方案


4.1 纯 ppapi 的局限

  硕正组件的功能中,有二个功能在 ppapi 插件环境下是无法实现:
1).反向调用页面 js, 受影响的在线演示例子如树列表的 “27.过滤 ” 中的 js()、硕正报表的 “10.自定义函数”;
2).事件是 post 的, 所以无法和 js 逻辑严格同步, 导致硕正全局函数 CancelEvent( ) 不起作用、以及导致树列表的例子 “26.自定义右键菜单 ”、报表的例子 “9.自定义工具条、自定义右键菜单” 无法正常弹出自定义的右键菜单, 这2个例子用到了 "MenuBeforePopup" 事件, 由于该事件在 ppapi 中只能异步发给页面, 主线程不阻塞, 不等你作出回应, 右键菜单已经弹出了;

4.2 何为内嵌 IE

  如果您的 B/S 应用必须要使用上述的这二个功能, 您可以选择使用另一个方案:内嵌 IE 内核.
  微软的 IE 浏览器,其底层是一个 ocx 控件, 即 “Microsoft Web Browser” 或 “Microsoft HTML Viewer”, 您在注册表中可以查到, 假如您精通 C# WinForm 或 VC、Delphi,想必不会对此陌生, 它能够被嵌入到其他 Windows 进程中。 我们在实现 ppapi 的开发过程中,在其内部增加了一个 ocx 的容器子窗口,可以让您的页面在插件内部的 IE 控件中运行!
  著名的国产软件金格软件,也是以这种方式实现 MS Office 在 Chrome 中展现的.

  本方案的原理模型示意图为:
  这种方案,需要 2 个页面来实现,外部的 Chrome 页面,只含有一个硕正 ppapi 插件, 让插件满幅显示; 其内部展现的是另一个页面:就是你真正想要的页面.
  内部页面的工作环境是 IE,所以不必考虑 ppapi 因素。

4.3 实现细节

  硕正官网的在线演示是双工的, “纯 ppapi” 模式 和 “内嵌 IE” 模式都支持, 在顶部备有下拉选择, 可以随时切换运行模式.
  下面我们来分析一下在线演示的一些技术细节, 内嵌 IE 的 “外部文件” 是根目录下的 ppapi-ie.htm。
  首先, 打开具体的某一个演示页, 都是由一小段 js 发起的, 以 Treelist 树列表为例, 请打开根目录下 top_treelist.htm 文件, 在文件的中间部分有一个 function navCur() 函数, 请看:
#65#function navCur()
{
 ..//略
 
#75# var url = 't' + (cur+1) + '.htm?107';    //所谓 “内部页面” 的 URL
 if($B.ppapi) {
  if(document.getElementById('ppapiMode').value == "ie") url = 'ppapi-ie.htm?' + url;  //下拉选择 纯ppapi模式 或 内嵌IE模式
 }
 window.parent.document.getElementById('ContentPage').src = url;  //打开演示页
}
  上面第 76、77 行是关键, 如果当前浏览器是 IE 或 npapi, 就不需要 “外部页面” 了,直接打开最终的 “内部页面” ; 否则就根据 <select> 下拉的选择, 如果您是选择了内嵌 IE, 则打开 “外部页面” , 并把 “内部页面” 的 URL 传递给它, 让它去处理.
  接下来我们看看 “外部页面” ppapi-ie.htm 是如何工作的:
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=GB2312">
<script language="JavaScript">
//该句相当于是 jquery 的 $(document).ready
document.addEventListener("DOMContentLoaded", addListener, false);
//为 pp 对象添加侦听
function addListener() {
 pp.addEventListener('message', handleMessage, false);
}
//ppapi对象的事件侦听
function handleMessage(message)
{
 if(message.data.name == "OnReady")
 {
  //URL拼装,比如把 "http://localhost/ppapi.htm?report1.htm" 转换成为 "http://localhost/report1.htm"
  var search = window.location.search;
  var url = window.location.href;
  url = url.substr(0, url.length - search.length);
  var n = url.lastIndexOf('/');
  if(n > 0) url = url.substr(0, n + 1);
  url += search.substr(1);
  //main: 插件的IE内核打开页面
  pp.postMessage( {func: 'Goto', para: url } );
 }
}
</script>
</head>

<body leftMargin="0" topMargin="0" rightMargin="0" bottomMargin="0" scroll=no style="overflow:hidden">
 <object id="pp" type="application/x-ppapi-supcan" Core="IE" isSilent="false" width="100%" height="100%">
  插件加载失败, 原因可能为:<br>
  1.硕正 ppapi 插件未正确安装;<br>
  2.当前 Chrome 不支持 ppapi, 请用高版本的 Chrome 浏览器
 </object>
</body>
</html>
  页面不复杂, 有几处需要说明一下.
1.Body 内就一个 <object> 插件, 没有其它元素, Body不需要滚动条, 边界统统设为0, 这样插件就满幅显示了;
2.<object> ... </object> 这中间的文字,是在插件创建失败才显示的;
3.<object> 中的 Core="IE",表示插件以内嵌 IE 方式运行;
4.插件创建完毕,会触发 OnReady 事件的, 所以要尽早侦听, 在页面加载完毕后马上要给插件添加侦听 (addEventListener);
5.在 OnReady 事件中,无非就是拆解、拼装出 “内部页面” 的 URL, 然后执行插件的 Goto 函数,让插件内部的 IE 控件去加载页面.