2.开发

问1.如何学习用硕正套件开发？

首先，您必须明白硕正套件相当于是客户端的中间件，它的容器是浏览器，要操控它，您必须具备页面开发的基本知识，比如html、javaScript、Ajax、CSS等。
由于是浏览器插件的关系，硕正套件与后端数据库是没有连接的，它只与应用服务器通讯：标准的 http 协议交互。为此，您必须精通一种后端开发的技能：JavaEE 或 ASP.Net.
单就硕正套件而言，如下是可参考的学习步骤：
1.学习左侧的《使用指南》，这是原理性的入门知识，对今后的开发和部署很有帮助；
2.从套件中选一种具体的组件入手，比如硕正树列表 或 硕正报表;
3.您可以结合这几种手段，逐步深入:
A.学习《开发者指南》中的具体组件的相关章节；
B.如果您是先从硕正报表入手，那么可以先观摩一下报表在线演示目录页左侧的几个视频，大致了解一下硕正报表的操作方式；
C.观看在线演示，按提示操作。请注意：我们绝大多数的演示页，在下方都有“技术分析区”，值得深入分析；
D.进一步解剖演示页的HTML源文件，源文件都在 demo 包中的根目录下，html文件名中的数字是和演示的顺序号对应的:
文件名前缀规则是：
t*.htm - 树列表的演示页，如t1.htm、t2.thm...;
f*.htm - 自由表头的演示页，如f1.htm、f2.thm...;
report*.htm - 报表的演示页，如report1.htm、report2.thm...;
other*.htm - 小型页面控件的演示页.
E.如果是研究树列表，需要同时参考顶部Tab中的《Treelist XML 文档规范》；
F.逐步尝试开发，把html转变成您自己的jsp或aspx, html部分可以对照我们的demo页照猫画虎就行;
G.重视本《常见问题解答》，这是我们整理的最常见的咨询问题;

问2.书写Treelist、Freeform的XML描述文件时，需要注意元素名、属性名的大小写吗？

不需要，硕正套件内置的XML解析器对大小写是不敏感的.

问3.我用asp.net开发了一个非常简单的页面，但是其中的硕正控件始终显示不出来，怎么回事？

解决方法一：把头上的这句话去掉：
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ... sitional.dtd">
解决方法二(建议)：用div包绕控件(需显式指定高宽)：

    <div style="width100%;height:400px">
     <script type="text/javascript">insertReport('AF','')</script>
    </div>

问4.OnReady() 是在页面事件onLoad( )前还是后触发？

不确定的。因为浏览器通常采用多线程渲染<div>、<td>中的内容，所以很难说哪个先完成。
如果你希望在OnReady( )和onLoad( )全部完成后做某项事情，最安全的做法是用一个计数变量，计数值达到某个数字时，再去执行程序。
在 Firefox 浏览器中，这个问题比较重要，请参看 “使用指南/11.不同浏览器的一些差异/11.3 OnReady 触发问题”。

问5.为什么我的页面经常会发生Supcan控件OnReady( )事件未触发的现象？

将该段 js 写到靠前一点(例如在Html的Head中)，这样就保证能触发。
在IE浏览器中，OnReady( )的触发时机是：在硕正组件首次显示时。假如你的页面很长(指高度)，需要用垂直滚动条往下拖时才显示硕正组件，那么在硕正组件初次浮现的一刹那， OnReady( )事件才被触发的！
还有一种情形，页面中控件的Table、div容器的高度(height)，如果你将其定义成百分比(例如 height="100%")，有可能也会导致该现象，因为我们发现，浏览器对百分比的高度的解析，在渲染过程中会有些不确定因素，建议您用js算出容器的高度，然后将高度修改成像素数.

问6.我将硕正套件集成在ExtJS中，比如安置在TabPanel中，但是发现OnReady( )事件报错: "AF为空或不是对象"，怎么解决？

最终插件肯定是安置在某个<form name="?" ...>中，请参考“使用指南”中的“9.Firefox和IE的一些差别”，你需要取得这个form的name。或者也可以用 document.getElementsByTags('form') 返回form的数组，如果只有1个form元素，也可以用 document.getElementsByTags('form')[0] 代替。
此外，如果遵照ExtJS的建议，采用iframe作为容器的话，是不存在这个问题的。

问7.InsertTreeList( )是在<div>中，再将其嵌到Table的<TD>中，为什么就看不见硕正组件了？

把<div>这一层去掉应该就可以。
对硕正组件来说，<div>、<td>相当于都是“容器”，有一个容器就已经够了。
如果选用<td>容器，通常还须确定<tr>的高度的像素数，否则组件仍有可能未显示。在Chrome浏览器中，甚至<td>中也必须明确高度的像素。

问8.我隐藏了含硕正控件的Div图层， jquery是这样写的： $("#divMain").hide(); ，再显示图层时，发现里面数据清空了，似乎控件被销毁后又重建了。在Chrome、Firefox下有这个问题，IE下没问题，这是怎么回事啊？

hide 是设置图层的 display 为 none，这样会导致里面的控件被自动销毁。请您重新写个隐藏的方法：设置 visibility 为 hidden 就可以了。

问9.我的网站在IE下完全正常，但为什么在FireFox下却发现同一个插件会多次触发OnReady( )事件？

可以肯定地说，一个插件只会触发一次OnReady( )。但是页面中样式发生变化时，FireFox可能会重新渲染一次的，导致插件被多次销毁、创建，每次创建肯定都会触发OnReady( )事件.
上面的 “问8...” 也是此问题的关键原因.

问10.我在页面中安置了多个控件，经常有些莫名其妙的问题，例如录入数据丢失、会自动刷新、甚至浏览器崩溃，但是单个控件的页面又是没问题的，什么原因？

可能性一: 你的OnReady( id )书写有问题，例如如下脚本就有严重问题：

    function OnReady( id )
    {
     AF1.func( ... );
     AF2.func( ... );
    }

从中可以看出页面中有2个控件实例，而2个实例各自会触发OnReady事件，也就是说这段js会执行2遍，在执行第一遍时，另外一个实例可能还没有被浏览器创建，这样就会发生难以预料的错误，这也是初学者容易忽视的地方。
正确的书写应该是：

    function OnReady( id )
    {
     if(id == 'AF1')
       AF1.func( ... );
     else if(id == 'AF2')
       AF2.func( ... );
    }

可能性二：假设你的页面一打开，控件之间就需要交互，如果你写成如下这样，也有大问题：

    function OnReady( id )
    {
     if(id == 'AF1') {
      AF1.func( ... );
     }
     else if(id == 'AF2') {
      var s = AF1.func( ... );   //在 OnReady('AF2')中访问其它对象：大忌
      AF2.func( ... );
     }
    }

问题出在第7行，因为这个时候AF1可能尚未创建，浏览器未必是按页面脚本的前后次序创建控件实例的。正确的写法可以参考如下的例子：

    var count = 0;  //计数器
    function OnReady( id )
    {
     count++;
     if(count==2) {  //OnReady( )2遍了，此时2个对象均已创建，下面的代码就很安全了
      AF1.func( ... );
      var s = AF1.func( ... );
      AF2.func( ... );
     }
    }

如下是一个更复杂的例子，请您分析一下问题的所在：

    var bReadyAF1 = false;
    var bReadyAF2 = false;
    var bReadyAF3 = false;
    function OnReady(id) {
      if (id == 'AFList') {
        AFList.func("Build", "build/base/OrgsList.xml");
        bReadyAF1 = true;
      }
      else if (id == 'AFPager') {
        AFPager.func("Build", "build/comm/Pager.xml");
        bReadyAF2 = true;
      }
      else if (id == 'AFEditForm') {
        AFEditForm.func("Build", "build/base/OrgsEdit.xml");
        bReadyAF3 = true;
      }

      if (bReadyAF1 && bReadyAF2) {
        var h = AFList.func("GetHandle", "");
        AFPager.func("BindPager", h + "\r\n pageID"); //绑定
        var url = "build/base/Org.ashx?Method=Orgs&StartRow=@startRow&Rows=@rows";
        AFPager.func("SetObjProp", "PageID \r\n dataUrl \r\n" + url + "\r\n mode=asynch ");
      }
      if (bReadyAF3) {
        WinEdit.hide();
      }
    }

可能性三：如果你的页面很长(指高度)，比如需要垂直滚动条, 如果插件一开始是隐藏在底部的，需要拖动滚动条才能显现，那么在IE中，插件是在初次显现时才会触发OnReady( )事件的!

问11.我在<script>insertFreeForm('AF', '')</script>下加了一句
<asp:Button ID="Button2" runat="server" Text="提交"/>后, 发现回车键不起作用了，怎么办？

<asp:Button >对应到Html是<input type="submit" >，浏览器将拦截submit的回车事件。
解决方法也很简单：将<script>insertFreeForm('AF', '')</script>安置在<Form>中、或将<asp:Button >安置在<Form>中就行。
如果这二者都在<Form>中，只要将其中一个移出<Form>就行。

问12.我的页面提交后，怎么组件中的数据全部丢失了？

原因就是：你的页面刷新了。 对于硕正套件而言，刷新相当于就是重新创建一遍控件实例、重新触发OnReady( )。所以为了保持状态，建议不要轻易使用刷新, 一般象<input type="submit" ...>、页面上传文件均会导致刷新, 原生的ASP.Net页面开发也经常会导致刷新。
页面和后端的交互应尽可能使用AJAX, 而不是提交页面。

问13.硕正演示页中有多种模式对话框方案，我该如何选择使用？

有3种方案，以下是方案的分析：
方案1：直接使用html的window.showModalDialog( )。这是浏览器本身就支持的对话框，对话框中是一个独立页面，易于开发，但很多程序员不喜欢它的界面风格；
方案2：使用能遮罩页面内容的js对话框，比如 Ext 的对话框, 界面比较美观，并且对话框中也是一个独立页面。如果您没有使用Ext，那么可以考虑使用 Treelist 演示页中一个改进后的 lhgdialog 对话框程序；
方案3：使用硕正套件内置的自定义对话框，对话框中是一个Freeform，并且该Freeform可以是URL，也可以是XML大串，比较适合于服务器端的动态生成，常用于诸如查询条件、单据查询等简单场合。自定义对话框分模式、非模式对话框二种，二者的差别在于：
A.非模式对话框, 是线程不阻塞的对话框，所以支持js的OnEvent事件交互，但开发稍复杂，并且其窗口被包容在组件内部；
B.模式对话框, 是Windows标准对话框，主线程是阻塞的，所以开发稍简单，但不支持js的事件交互、对话框打开期间不能切换浏览器的选项卡(Tab)、并且对Firefox浏览器支持不好(易僵死)；

问14.我的 div 弹出层会被硕正控件遮挡，这该怎么办？

可以从一下几个方面来分析、解决:
1.如果您是用 Ext-JS 框架, 就不存在这个问题, 只要设置 Ext.useShims = true; 就能解决；
2.如果您是用 Chrome ppapi 模式, 执行全局函数 GrayWindow 就能让硕正控件暂时不遮挡, 树列表的在线演示 "35.遮罩效果" 演示了效果;
3.如果没有采用 ExtJS框架, 单纯的 div 确实会被控件遮挡的, 这也是控件类页面元素的硬伤, 但 iframe 是不会被遮挡的，所以建议你将弹出层移入 iframe 中。你可以试一下例如下面的 html：

    <div id="cover" style="position:absolute;left:90px; top:200px; width:400px;height:400px">
      <iframe src="index.htm" width="100%" height="100%"></iframe>
    </div>

也可以在被挡的 div 层的底部增加一个透明度为 0 的 iframe, 以 easyui 为例；

    <div class="menuBar">
     <div class="menuMain">
      <a href="javascript:void(0)" id="mb1" class="easyui-menubutton" data-options="menu:'#mm1',iconCls:'icon-edit'">设备统计</a>
      <a href="#" class="easyui-linkbutton" data-options="plain:true" onclick ="Marker()" >标记</a>
      <a href="#" class="easyui-linkbutton" onclick ="jieTui()" data-options="plain:true">截图</a>
     </div>
     <div id="mm1" style="width:150px;" class="selectMenu">
      <!-- 下面一行为透明度为 0 的 iframe, 作为衬底 -->
      <iframe frameborder= "0" scrolling="no" style="background-color:transparent; position:absolute; z-index: -1; width:100%; height:100%; top:0; left:0;"></iframe>
      <div data-options="iconCls:'icon-save'" onclick ="dvrRecord()">DVR设备</div>
      <div data-options="iconCls:'icon-save'" onclick ="Firehost()">消防主机</div>
      <div class="menu-sep" ></div>
     </div>
    </div>

我们在所有浏览器下都测过，iframe 部分不会被遮挡。请注意 z-index, 如果 z-index 不正确, 仍然会被遮住.
4.最后, 还有一种解决方案：用硕正的自由表头 (Freeform) 去开发一个工具条, 来代替你的div层，请参考自由表头例子 " 5.事件、按钮、菜单、工具条"、“6.动态更改属性(1)”，相信你能开发得出来的。

问15.FireFox访问页面元素都需要采用 getElementById() 或 getElementByName() 函数，访问插件也需要这样写吗？

不需要，因为插件是一种特殊的页面元素，可以直接访问，本demo页中均是这样写的。在这一点上，所有浏览器是没区别的.

问16.在Firefox 4.0下，发现在OnEvent( )事件中调用js函数 alert( ) 后浏览器有时会死机，如何解决？

请用全局函数 MessageBoxFloat 代替 alert( ) 吧，原因请参看 “开发指南/11.不同浏览器的一些差别/11.4 线程阻塞问题”.

问17.我的网站在IE下完全正常，但在FireFox、Chrome下有很多问题，怎么办？

HTML、CSS、JavaScript、正则表达式本身在IE和FireFox、Chrome下就有不少的差别，你需要先搞定和硕正套件无关的那些内容.

问18.当Session过期时，执行Load加载不到数据，能否让客户端有个提示？

请参考开发者指南的《公共内容》下的“4.XML/JSON异常包”，相信您会满意!

问19.从安全考虑，我后端的程序需要甄别哪些请求来自页面、哪些来自硕正套件。怎么才能知道 request 请求是来自硕正套件的？

从硕正插件发起的http请求，它的http头大多是这样的格式：

    GET /supcan/treelistdata/data.txt HTTP/1.1
    Accept-Encoding: gzip, deflate
    Content-Type: text/html; charset=UTF-8
    User-Agent: BC
    Host: localhost:8081
    Cache-Control: no-cache

里面的 "User-Agent" 固定是 "BC"，你只要判断这个属性就行。

问20.我看到几乎所有demo页源码的底部都执行了 nstd.js，我们自己的页面有必要使用这个js吗？

没有必要，执行该js反而会影响性能。该js是硕正demo页格式化示例源码显示用的。

问21.有时候敲“BackSpace”键会导致页面回退，即回到上一个页面，如何避免这种现象？

如果当前焦点是硕正控件，应该是不会发生这种情况的，否则是有可能的，因为这个时候键盘的控制权不在控件。但是我们可以给您一个建议：请在页面按钮的js脚本的末尾处添加一句诸如：focusIE(AF)，该语句的作用是把焦点切换给控件 (此函数在 dynaload.js 中)。

问22.在 IE 下发现某些页面的 Treelist 或 Report的回车键都不起作用，怎么回事呢？

请检查一下您的页面源码，是否包含了 <button> 页面元素，因为在 IE 中 button 将独占回车事件，硕正控件无法获得。将 <button> 换成 <input type="button" ...> 即可。

问23.我后端一进入调试(Debug)，发现浏览器就僵死，这正常吗？

正常，因为控件一直等着服务器返回 response 呢！

问24.刚进入页面时，控件区域有明显的黑屏闪烁，能否除去这个闪烁？

进入页面时，控件将自动在周边区域查找相近的颜色作为底色，但有时未能正确找到，就导致了这个黑屏，比如 html 中的 <Body> 边界设为 0、控件满屏显示时极易出现黑屏，你可以尝试将边界设为1:

     <body topmargin=1 leftmargin=1 rightmargin=1 bottommargin=0 >
     ...

问25.我用 jQuery 动态插入硕正组件不成功，怎么办？ 如下是我的代码

     var str = "<div id='DV_Print' style='position:relative;width:96%;height:300px'><script" + ">";
     str += "insertReport('AF2', 'rebar=none')";
     str += "<" + "/script></div>";
     $(document.body).append(str);
     ..

是的，jQuery的 append( ) 不能直接调用 insertReport( ), 而是应该调用 insertReport( ) 的底层函数，您打开 dynaload.js 看一下，它调用的是 bldStr( ) 函数，你该调用的就是此函数，这样写就没问题了：

     var str = "<div id='DV_Print' style='position:relative;width:96%;height:300px'>";
     str += bldStr('LuxForm', 'AF2', 'rebar=none', '100%');
     str += "</div>";
     $(document.body).append(str);
     ..

此外，动态创建硕正插件要注意二点：
1.新创建的插件也会触发 OnReady( ) 事件的，请注意你的代码写法，因为 OnReady( ) 是单一入口的，所以请务必为 'AF2' 单独增加一个条件判断;
2.不要忘记，$(document.body).append(str) 的时刻，和 OnReady( ) 的触发时刻，会有个时间差的，你不能紧挨着动态创建的 js 代码后面立即执行 AF2 的函数.

问26.我开发出来的程序，浏览器很卡，一般是什么原因？

极有可能是你后端程序响应慢，建议你打开 httplog (请看《附录2.Reg.ini配置》) 检查一下。
硕正插件尽管尽可能让取数的 http 实现异步，但大部分的 http 请求仍然是同步的 (例如加载模板)，同步模式是需要在当前主线程下等待后端响应的，如果响应时间过长，就表现为浏览器卡死。

问27.我开启浏览器的debug, 发现有这种错误，怎么办？

不必理会这个错误，原因是：硕正控件在运行过程中不不断抛出事件，事件是通过反向调用页面的 OnEvent 函数实现的，如果你的页面没有写这个函数，那么浏览器会认为是个错误。
当然，你只要在页面中写OnEvent函数，就不会有这个提示了, OnEvent是硕正指定的事件函数，请参考《使用指南》的“9.事件”。
如果你的页面不需要响应硕正的事件, 那么请写一个空的函数体，就不会弹出上述误报了:

    function OnReady(id)
    {
     AF.func("Build", "../../report/shd1.xml");
    }
    function OnEvent(id, Event, p1, p2, p3, p4)
    {
    }

问28.我开发的页面，在IE下完全正常，但在 360 浏览器兼容模式下却无法加载数据, 我跟踪并截取了 http 请求(见下方), 发现和 IE 下的请求相比, Cookie多出了带乱码的 "theworld_client_none=潮敮" 这一截，请问这该如何解决啊?

    Content-Type: text/html; charset=UTF-8
    User-Agent: BC
    Host: 127.0.0.1:8081
    Cache-Control: no-cache
    Cookie: JSESSIONID=5D325BB13A7215C8B373B1F9D128C5E9; theworld_client_none=潮敮

tomcat7对中文支持有问题，开发环境换一下就可以了。另外，这多出来的 "theworld_client_none" 条项是 360 浏览器加上去的，有人在2015年已经反应给360公司了，但一直没得到回复，原因不明.