{"title":"编码和调试","inframe":false,"hidden":false,"roles":{"demo":1,"dev":1},"pageLink":"","children":[{"configs":{"itemId":"module"},"children":[{"configs":{"layout":"fit","itemId":"viewport1"},"children":[{"configs":{"autoScroll":"true","html":"<div class=\"wb_doc\">\n  <h2>编码和调试<\/h2>\n  <hr class=\"wb_hr\">\n  <h3>服务器端编程<\/h3>\n  <p>可以通过两种方法进行服务器端编程，一是基于JS语法的Java实现编程（以下简称为ServerScript，以区分JavaScript），二是使用纯Java。前者是指JS在Java上的实现，即Rhino、Nashorn或其他相关框架。<\/p>\n  <p>WebBuilder针对这两种方法分别提供了工具类库和API方法，以方便快速编程。在ServerScript中，提供了全局工具方法类库server.js，该文件位于wb/system/server.js，开发人员可根据需要扩充其中的方法。<\/p>\n  <hr class=\"wb_hr\">\n  <h3>客户端编程<\/h3>\n  <p>在客户端编程通常指使用JS进行编码。在module的loadJS属性中可以选择一种或多种预定义的js框架，或在cssLinks和jsLinks中自定义js和css的引用。WebBuilder也支持动态的方式引用js/css链接，任何子模块必须通过该方式引用js/css。我们建议通过动态的方式加载js/css，因为这样的加载方式更高效和节省资源，可充分实现资源按需加载。<\/p>\n  <hr class=\"wb_hr\">\n  <h3>作用域和app对象<\/h3>\n  <ul>\n    <li><b>客户端app对象<\/b><\/li>\n    <p>每个模块的客户端JS脚本中，默认都提供app对象，所有控件生成的实例都关联到该app对象。访问当前页面的某个控件实例可通过app.itemId来访问，访问其表达式定义可通过app._itemId来访问。如果itemId重复，只返回第一个指定名称的对象。对于itemId重复控件的访问，可通过逐级引用来访问，如panel1.getComponent('panel2').getComponent('text1')。我们可以指定控件的normalName属性来为控件指定新的别名，该别名优先级高于使用itemId指定的名称，比如指定itemId为store的normalName为myStore，则可通过app.myStore来访问该控件。通常对于这些控件的引用和赋值有更好的方法来处理，比如使用Wb.getRefer,Wb.getValue,Wb.setValue等方法：<\/p>\n    <ul>\n      <li>Wb.getRefer：获得指定控件及其所有子控件的引用，如Wb.getRefer(app.panel1)将获取panel1下所有子控件的引用。<\/li>\n      <li>Wb.getValue：获得指定控件及其所有子控件的值组成的对象，其itemId属性为名称，如Wb.getValue([app.panel1,app.window1])。<\/li>\n      <li>Wb.setValue：设置指定控件及其所有子控件的值，如Wb.setValue(app.panel1,{text1: 'abc', number1: 123}，text1和number1分别为panel1的子控件。<\/li>\n      <li>还有其他诸多方法，在此不一一赘述，详细请参考API手册。<\/li>\n    <\/ul>\n    <p>app的作用域为模块内部，不同模块之间的互相访问可通过如下方式：<\/p>\n    <ul>\n      <li>举例1：模块A内添加itemId为myXwl的xwl控件指向模块B，在模块A内使用app.myXwl即指向模块B的app。<\/li>\n      <li>举例2：模块A的panel1作为模块B的window1的一个子控件，那么通过模块B的app.moduleA.panel1或app.window1.down('#panel1')即可找到模块A的panel1引用，通过app.moduleA属性可找到模块A的整个app。<\/li>\n      <li>举列3：如果使用Wb.run的方法动态调用，在回调函数中会传递app参数；<\/li>\n      <li>举例4：如果使用card=Wb.open(config)打开指定模块后，通过card.appScope即可访问到指定模块的scope对象。<\/li>\n      <li>举例5：设置module的itemId为非\u201cmodule\u201d的任意名称即可生成全局命名空间。如果使用全局命名空间，则该命名空间只能生成一个实例，因为同一命名空间的多个实例将产生混淆。<\/li>\n    <\/ul>\n    <li><b>ServerScript app对象<\/b><\/li>\n    <p>在ServerScript中提供了当前请求相关的app对象，该对象绑定了当前请求相关的request和response。在该对象中提供了相关的方法，具体方法使用请参考API文档：<\/p>\n    <ul>\n      <li>app.log：在客户端控制台中输出日志信息对象。<\/li>\n      <li>app.info：在客户端控制台中输出提示信息对象<\/li>\n      <li>app.warn：在客户端控制台中输出警告信息对象。<\/li>\n      <li>app.error：在客户端控制台中输出错误信息对象。<\/li>\n      <li>app.send：发送指定对象到客户端。<\/li>\n      <li>app.get：获取request指定名称或所有参数/属性组成的对象。<\/li>\n      <li>app.fetch：获取request指定名称或所有参数/属性组成的对象，并把对象值转换为JS值。<\/li>\n      <li>app.set：设置request指定名称的属性值。<\/li>\n      <li>app.run：运行SQL语句，并获取返回结果。<\/li>\n      <li>app.output：按特定格式输出SQL语句返回的结果到客户端。<\/li>\n    <\/ul>\n  <\/ul>\n  <hr class=\"wb_hr\">\n  <h3>调试<\/h3>\n  <p>在服务器端调试ServerScript可以使用app中定义的控制台方式，这些方法可输出对象而非字符串至客户端，如app.log({foo: 'bar', abc: 123})将在当前用户的客户端控制台输出该JSON对象。另外如果开发人员安装了相关Java开发工具，如IntelliJ IDEA，Eclipse等，可以对ServerScript、Java或二者的混合代码进行断点，单步，步进，步出等调试。<\/p>\n  <p>在客户端调试JavaScript除了可以使用Cs.log，Cs.info等方式输出对象外，还可以使用浏览器带的开发者工具进行调试。推荐使用Chrome开发者工具，该工具提供了完善的代码断点，单步，步进，步出，资源查看，网络、资源、审计等诸多调试功能。在早期版本的Chrome开发者工具中，在线修改代码后如果在调试工具下代码未同步更新，我们可以通过按两次F12刷新控制台或双击模块的Tab标签在新窗口中打开来调试。<\/p>\n  <p>在IDE中，Ide.activeCard表示当前选择的tab选项卡，Ide.activeScope表明当前模块的app对象。获取对象后可以在控制台中方便进行调试。每个页面都可以通过app对象访问主模块，如在新页面中打开数据库浏览器，那么全局变量app就是数据库浏览器的app域。<\/p>\n  <hr class=\"wb_hr\">\n  <h3>No IFrame模式的页面加载<\/h3>\n  <p>当一个模块使用no iframe模式加载时，只有自动创建实例的容器控件才会作为主界面被自动加载和显示。系统会自动选择一个最优先的容器控件作为主界面加载到主应用，其优先顺序为itemId为main的容器,viewport/container,panel,form,tabpanel和fieldset。如果没找到以上控件，则把第一个容器控件作为主界面加载到主应用。<\/p>\n  <p>如果所有容器的createInstance属性为false或在代码中使用return null（如在finalize事件return null）来返回空的app，那么系统将不会自动加载主页面。此类情况，开发人员一般可通过编码的方式来选择手动加载。<\/p>\n  <hr class=\"wb_hr\">\n  <h3>模块脚本输出至客户端<\/h3>\n  <p>可以使用WebUtil.send或app.send(ServerScript)方法发送脚本、流或其他任何对象至客户端。如果模块存在可输出的客户端脚本，系统会自动输出这些脚本。在某此情况下，如果我们不希望系统自动输出脚本可以设置module的createFrame属性为false，或在编码中在输出内容之后，调用response.flushBuffer方法。如果内容已经提交，那么系统将不再发送这些客户端脚本。<\/p>\n<\/div>","itemId":"panel1","border":"false"},"children":[],"type":"panel","expanded":false}],"type":"viewport","expanded":true}],"type":"module","expanded":true}],"iconCls":""}