nbhkdz.com冰点文库

2015-jQuery实例教材911

时间:2016-01-02


(jQuery+EasyUI 版)

2015 年 9 月





第 1 章、jQuery 及其开发环境 ................................................................................................................... 1 1.1 J2EE 开发环境简介 ....................................................................................................................... 1 1.2 安装 Tomcat 服务器 ...................................................................................................................... 1 1.3 安装 MyEclipse.............................................................................................................................. 6 1.4 导入和建立工程文件 jQDemos .................................................................................................. 10 1.5 添加和配置 MyEclipse 中的 Tomcat6.x 服务器 ........................................................................ 14 1.6 部署 jQDemos 工程文件............................................................................................................. 16 1.7 安装和生成 emlab 数据库 .......................................................................................................... 19 1.8 SQL Server2008 的网络配置 ....................................................................................................... 20 第 2 章、EasyUI 基本表单控件 ................................................................................................................ 23 实例 1. 创建 EasyUI 表单及常用控件。 ......................................................................................... 23 实例 2. EasyUI 表单及其控件的 jQuery 语句设计。 ...................................................................... 25 实例 3. 利用绝对坐标实现表单控件的位置布局。 ....................................................................... 28 实例 4. 利用 append()方法在 jQuery 中动态定义和生成 EasyUI 控件。 ..................................... 31 实例 5. 构造控件自定义函数,简化控件的使用。 ....................................................................... 32 实例 6. 控件定义函数的综合应用。 ............................................................................................... 36 实例 7. 使用 tabs 标签页控件分页显示多个表单控件。 ............................................................... 38 实例 8. 静态组合框 combobox 控件及其事件和初值的设置。 .................................................... 39 实例 9. 利用滑块(slider)控件实现图片的等比例缩放。 .......................................................... 40 实例 10. 工具栏、菜单和消息框控件的使用。 ............................................................................. 43 实例 11. 窗口控件 window 的应用及其函数构造。 ...................................................................... 46 实例 12. 利用布局(layout)控件实现页面布局。 ....................................................................... 46 实例 13. 获取表单中可编辑控件的名称、类型及其值。 ............................................................. 48 实例 14. 表单的键盘控制与控件聚焦。 ......................................................................................... 49 实例 15. 利用文件框控件 file 实现文件的上传。 .......................................................................... 51 实例 16. 服务器端文件下载的实现。 ............................................................................................. 54 第 3 章、EasyUI 数据库控件 .................................................................................................................... 57 实例 17. 构造连接数据库 Java 类,实现数据查询操作。 ............................................................ 57 实例 18. 服务器端数据更新语句的执行。 ..................................................................................... 59 实例 19. 服务器端存储过程和用户定义函数的调用。 ................................................................. 61 实例 20. 动态 combobox 组合框控件的定义与初值设置。 .......................................................... 62 实例 21. 动态 combobox 组合框控件之间联动效果的实现。 ...................................................... 64 实例 22. 服务器端取数据库中数据赋值到表单。 ......................................................................... 65 实例 23. 客户端和服务器端表单数据验证。 ................................................................................. 67 实例 24. 服务器端数据库记录的增删改操作。 ............................................................................. 69

实例 25. 服务器端 SQL 脚本文件.sql 的运行。 ............................................................................. 74 第 4 章、树与数据网格及其应用 ............................................................................................................. 78 实例 26. 静态树 Tree 控件及其基本操作。 .................................................................................... 78 实例 27. 基于 JSON 数据的静态树加载与操作。.......................................................................... 80 实例 28. 从数据库一次性加载数据到树节点。 ............................................................................. 84 实例 29. 动态树节点的分层逐级加载。 ......................................................................................... 87 实例 30. 动态组合树 ComboTree 控件及其应用。 ........................................................................ 91 实例 31. 静态 JSON 数据网格控件基础。 ..................................................................................... 93 实例 32. 动态数据库网格控件及其分页处理。 ............................................................................. 95 实例 33. 数据库网格中数据的过滤与定位。 ................................................................................. 98 实例 34. 可编辑数据网格及其数据增删改操作的实现。 ........................................................... 103 实例 35. 数据网格的表单关联扩展。 ........................................................................................... 107 实例 36. 树形网格(TreeGrid)的综合应用。............................................................................. 110 第 5 章、图表统计及其应用 ................................................................................................................... 119 实例 37. FusionCharts 单序列图表及应用。 .................................................................................. 119 实例 38. FusionCharts 多序列图表及应用。 .................................................................................. 122 实例 39. FusionCharts 图表向下钻取。.......................................................................................... 124 实例 40. 带多层表头和汇总行的数据网格及其 Excel 文件输出。 ............................................ 130 附录 1、jQDemos 自定义控件函数........................................................................................................ 136 附录 2、JavaScript 常用函数 .................................................................................................................. 144

《软件开发工具(jQuery) 》实例教程

第 1 章、jQuery 及其开发环境
jQuery 是继 prototype 之后又一个优秀的 Javascript 库。它是轻量级的 JS 库 ,兼容 CSS3 和 各种浏览器(IE 6.0+, FF 1.5+, Safari 2.0+, Opera 9.0+),jQuery2.0 及后续版本将不再支持 IE6/7/8 浏览器。 jQuery 能更方便地处理 HTML 和为网站提供 AJAX 交互。 jQuery 另一个比较大的优势是 其文档说明齐全,同时还有许多成熟的插件可供选择。 jQuery 的核心理念是 write less、do more(写得更少,做得更多),最早在 2006 年 1 月由美 国人 John Resig 发布。如今,jQuery 已经成为最流行的 javascript 库,在世界前 10000 个访问最多 的网站中,有超过 55%在使用 jQuery。 jQuery 是免费、开源的,使用 MIT 许可协议。jQuery 的语法设计可以使开发者更加便捷,例 如操作文档对象、选择 DOM 元素、制作动画效果、事件处理、使用 Ajax 以及其他功能。除此以 外,jQuery 提供 API 让开发者编写插件。其模块化的使用方式使开发者可以很轻松的开发出功能 强大的静态或动态网页。 jQuery,顾名思义,也就是 JavaScript 和查询(Query),即辅助 JavaScript 开发的库。

1.1 J2EE 开发环境简介
? ? ? ? ? 服务器:Tomcat6.0 及以上。 数据库:SQL Server2008。 程序开发环境:MyEclipse6.5 及以上。 程序设计语言:客户端 Javascript(JS) 、服务器端 JSP、JAVA。 jQuery 插件库:EasyUI 等。

1.2 安装 Tomcat 服务器
1.2.1 Tomcat6.0 及安装步骤
将文件夹 apache-tomcat-6.0.30 复制到 C 盘根目录下,即可完成 Tomcat6.0 的安装过程,这时 C:\ apache-tomcat-6.0.30 文件夹下包括图 1-1 所示内容:

图 1-1

Tommcat6.0 文件目录 -1-

《软件开发工具(jQuery) 》实例教程

1.2.2 安装 JDK
打开 C:\Program Files\Java 这个文件夹,如果存在 jdk*和 jre*两个子文件夹,表明 Windows 系统已经安装了 JDK,如果不存在 C:\Program Files\Java 及其子文件夹,则需要安装 JDK。对没 有安装 JDK 的操作系统,下面以 jdk-7 为例,阐述 JDK 安装过程。 ①点击安装程序,开始安装过程。选择 JDK 默认安装路径(如图 1-2 所示) ,不作更改。

图 1-2

JDK 安装过程(选择默认安装路径)

②同样安装 JRE 时选择默认安装路径, 即与 JDK 安装在同一个 java 文件夹下 (如图 1-3 所示) 。 安装成功后关闭窗体。

图 1-3

JRE 安装过程(选择默认安装路径)

-2-

《软件开发工具(jQuery) 》实例教程

图 1-4

JDK 安装结束界面

1.2.3 设置 JDK 环境变量
以 Win7 为例(如果已经安装 JDK,直接设置环境变量) : ①右击“我的电脑”,选择“属性”,选择“高级系统设置”,这时出现图 1-5 界面。

图 1-5

JDK 环境变量配置(选择高级系统设置)

②点击上图中的“环境变量”按钮,在“系统变量”中新建 JAVA_HOME 变量。变量值填写 JDK 的安装目录(例如 C:\Program Files\Java\jdk1.7.0_4⑤。

图 1-6

JDK 环境变量配置(新建 JAVA_HOME 变量)

-3-

《软件开发工具(jQuery) 》实例教程 ③系统变量中找到 Path 变量,点击“编辑”(如图 1-6 所示) 。在变量值这一栏中输入: %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin; 注意:最后一个分号必须输入。

图 1-6

JDK 环境变量配置(编辑 PATH 变量)

④在“系统变量”中新建 CLASSPATH 变量(如图 1-7 所示) 。变量值填写如下: .;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar 注意:最前面有一个点。系统变量配置完毕,按“确定”按钮退出。

图 1-7

JDK 环境变量配置(新建 CLASSPATH 变量)

⑤检验是否配置成功。 运行 cmd (或在命令行中) 输入 java -version (注意: java 和 -version 之间有空格) 。若出现图 1-8 所示结果,显示 JDK 版本信息,则说明 JDK 安装和配置成功。

图 1-8

JDK 环境变量配置成功

⑥重启计算机,JDK 环境变量设置方可生效。

1.2.4 Tomcat6.0 的启动和停止
①打开 C:\ apache-tomcat-6.0.30\bin 文件夹,点击其中的 startup.bat 文件,即可启动 Tomcat6.0 服务器,这时屏幕上出现图 1-9 所示信息,表明 Tomcat 服务器已经开启并将一直保持运行状态。

-4-

《软件开发工具(jQuery) 》实例教程

图 1-9

Tomcat6.0 启动运行界面

②也可以通过打开一个游览器(建议使用 Google 的 Chrome 游览器) ,在游览器地址栏输入 下列地址:http://127.0.0.1:8080。如果出现图 1-10 所示页面,则表明 Tomcat 安装成功并已启动。

图 1-10

Tomcat 配置成功启动页面

③在 startup.bat 所在的同一文件夹中, 点击其中的 shutdown.bat 文件, 即可停止和关闭 Tomcat 服务器。 注意: 在安装 MyEclipse 之后, 通常在 MyEclipse 开发环境中开启和关闭 Tomcat 服务器。 这时需要按照上一步的操作方法,关闭 Tomcat 服务器,否则在 MyEclipse 无法开启服务器。

1.2.5 设置 Tomcat 端口号
在启动 Tomcat 的过程中,有些系统可能会出现错误,其中一种可能是端口号 8080 与其他应 用程序发生冲突,这时需要修改或重新设置端口号。重新设置端口号的方法如下: ①在 C:\apache-tomcat-6.0.30\conf\文件夹中,用记事本打开编辑 server.xml 配置文件; ②在该文件中搜索 8080 字符串 (如图 1-11 所示) , 将下列行中的 port="8080"改成 port="8088":

图 1-11

Server.xml 配置文件查找 8080 端口 -5-

《软件开发工具(jQuery) 》实例教程
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> 改为: <Connector port="8088" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> <Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> connectionTimeout="20000" redirectPort="8443" /> 改为: <Connector executor="tomcatThreadPool" port="8088" protocol="HTTP/1.1"

③保存 server.xml 文件后退出,重新启动 Tomcat,然后在游览器中输入下列地址: http://127.0.0.1:8088

1.3 安装 MyEclipse
这里以 MyEclipse6.5 为例,描述安装过程。 ①点击打开安装文件,开始安装过程(如图 1-12 所示) 。

图 1-12

运行 myEclipse6.5 安装程序

-6-

《软件开发工具(jQuery) 》实例教程 ②选择默认路径安装(如图 1-13 所示) 。

图 1-13

选择默认路径安装 myEclipse6.5

③点击“Install”正式开始安装(如图 1-14 所示) 。

图 1-14

正式开始 myEclipse6.5 安装过程

④正在安装,请稍候(如图 1-15 所示) 。

图 1-15

myEclipse6.5 安装过程进行中

⑤安装完毕后,选择“Launch MyEclipse6.5”,关闭“Open the release notes”,这时安装程序将 打开和启动 MyEclipse(如图 1-16 所示) 。
-7-

《软件开发工具(jQuery) 》实例教程

图 1-16

myEclipse6.5 安装成功结束

⑥启动进入 MyEclipse,需要几分钟(如图 1-17 所示,有点慢哦) 。

图 1-17

启动打开 myEclipse6.5 程序

⑦输入 Workspace 工作目录 (例如 d:\myjsp, 如图 1-18 所示) ; 在后面复选框中 (Use this as the default and do not ask again)打上勾,然后点击 OK 按钮。

图 1-18

配置 myEclipse6.5 的工作文件目录

⑧这时出现 MyEclipse 编辑界面。稍后在屏幕会跳出一个子窗体,要求输入注册码。

图 1-19

提示输入 myEclipse6.5 注册码和序列号 -8-

《软件开发工具(jQuery) 》实例教程 ⑨点击“Enter Subscription …”,输入用户名和注册码如下(如图 1-20 所示) 。 administrator nLR8ZC-855550-60675256396752354

图 1-20

输入 myEclipse6.5 注册码和序列号

⑩如果需要重新注册,可在工具栏中点击 Window+Preferences 菜单,在菜单树中找到 MyEclipse Enterpise Workbence 之下的 Subscription 菜单(如图 1-22 所示) ,点击该菜单后在右侧 屏幕中输入注册码。

图 1-22

修改 myEclipse6.5 注册码和序列号

-9-

《软件开发工具(jQuery) 》实例教程 ①关闭 MyEclipse 的 Welcome 栏目,出现下列 MyEclipse 工作环境,至此 MyEclipse 安装结 束(如图 1-23 所示) 。

图 1-23

myEclipse6.5 程序设计与调试环境

1.4 导入和建立工程文件 jQDemos
①将 jQDemos.rar 文件复制到 d:\myjsp 文件夹中,这个文件夹中一开始时只有一个子文件夹 和这个压缩文件(如图 1-24 所示) 。

图 1-24

jQDemos 工程文件解压

②按右键将 jQDemos.rar 解压到当前文件夹(即 d:\myjsp 文件夹)下(如图 1-25 所示) 。

图 1-25

jQDemos 工程文件解压后的文件夹

- 10 -

《软件开发工具(jQuery) 》实例教程 ③返回到 MyEclipse 程序设计环境(如图 1-26 所示) ,点击工具栏中的 File+Import 菜单,导 入工程文件夹 jQDemos。

图 1-26

选择导入 jQDemos 工程

④在下图中选择 Existing Projects into Workspace 菜单,点击“Next”按钮(如图 1-27 所示) 。

图 1-27

选择从现有的工程中导入 jQDemos 到工作文件夹

- 11 -

《软件开发工具(jQuery) 》实例教程 ④点击下图中的 Browse 按钮,在弹出的子窗体中选择 d:\myjsp\jQDemos 文件夹(如图 1-28 所示,注意不要选择后面的子文件夹)

图 1-28

导入 jQDemos 工程时选择文件夹为 jQDemos

⑤点击上图 1-28 中的“确定”按钮,出现图 1-29 所示界面。在图 1-29 的 Copy projects into workspace 中打上钩;点击“Finish”按钮。

- 12 -

《软件开发工具(jQuery) 》实例教程

图 1-29

导入 jQDemos 工程结束

⑥这时在 MyEclipse 中出现下列界面(如图 1-30 所示) ,即已经存在一个工程文件 jQDemos。

图 1-30

导入 jQDemos 工程成功

- 13 -

《软件开发工具(jQuery) 》实例教程

1.5 添加和配置 MyEclipse 中的 Tomcat6.x 服务器
①在 MyEclipse 中点击 Window+Preferences 菜单(如图 1-31 所示) 。

图 1-31

在 myEclipse6.5 中配置 Tomcat6.0

②在图 1-32 所示的左侧菜单树中输入框“type filter text”中输入“tomcat”这个字符进行过滤; 在 菜单树选中 Tomcat 6.x;点击右侧的第一个 Browse 按钮,选中 Tomcat6.0 所在的文件夹位置(不 要点击到子文件夹哦) ,即 C:\apache-tomcat-6.0.30。点击“确定”按钮。

图 1-32

选择 Tomcat6.x 所在的文件夹

③这时屏幕出现图 1-33 所示界面。点中右上侧的无线按钮“Enable”,再点击 OK 后,屏幕关 闭,返回到 MyEclipse 界面,这时 Tomcat 配置结束。

- 14 -

《软件开发工具(jQuery) 》实例教程

图 1-33

选中 Tomcat6.0 文件夹并激活

④开启 myEclipse 中的 Tomcat6.x 服务器。先使用 shutdown.bat 关闭命令行中的 Tomcat 服务 器(方法见 1.2.4) ,点击 MyEclipse 工具栏中的“Start”小按钮,选择 Tomcat 6.x+Start 菜单(如图 1-34 所示) 。

图 1-34

在 myEclipse6.5 中启动 Tomcat6.0

这时屏幕下方出现下列信息 (如图 1-35 所示) , 至此 Tomcat 服务器在 MyEclipse 中配置结束。

图 1-35

myEclipse6.5 中启动 Tomcat6.0 成功提示信息

- 15 -

《软件开发工具(jQuery) 》实例教程

1.6 部署 jQDemos 工程文件
①点击 MyEclipse 窗体工具栏中的一个“部署”(Deploy)小按钮(如图 1-36 所示) 。

图 1-36

myEclipse6.5 中部署 jQDemos 工程

②这时屏幕出现图 1-37 界面。在 Project 组合框中选中 jQDemos(其实这时只有这个选项) 。

图 1-37

myEclipse6.5 中将 jQDemos 工程部署到 Tomcat6.0 中去

③点击上图 1-37 右侧的“Add”按钮,出现图 1-38 界面。在 Server 组合框中选中“Tomcat 6.x”。

图 1-38

myEclipse6.5 中选择 Tomcat6.0 服务器

- 16 -

《软件开发工具(jQuery) 》实例教程 ④点击图 1-38 中的“Finish”按钮,这时出现部署工程项目文件的过程(如图 1-39 所示) 。

图 1-39

myEclipse6.5 提示正在部署 jQDemos 工程到 Tomcat6.0

⑤部署完成后,出现图 1-40 所示界面。此时,点击“OK”按钮,关闭部署过程。第二次部署 某个工程时,可以点击“Redeploy”(重新部署)按钮。

图 1-40

myEclipse6.5 中部署 jQDemos 工程成功

⑥程序编辑。打开 jQDemos 文件夹+WebRoot,找到 example01_basicform.jsp 程序。这时可能 出下列屏幕(如图 1-41 所示) ,暂时无法看到该程序的源码。

- 17 -

《软件开发工具(jQuery) 》实例教程

图 1-41

myEclipse6.5 中打开 jQDemos 工程文件

点击图 1-41 中上面的小图标按钮或关闭 example01_basicform.jsp 程序再打开,这时屏幕窗体 正常,出现源程序代码如下(如图 1-42 所示) :

图 1-42

myEclipse6.5 中编辑 jQDemos 工程文件

⑦安装和打开 Google 的 Chrome 游览器;在游览器中输入下列地址: http://127.0.0.1:8080/jQDemos/example02_formcontrols.jsp.jsp。这时出现图 1-43 所示的程序运行界 面页面,至此 J2EE 环境安装成功。

- 18 -

《软件开发工具(jQuery) 》实例教程

图 1-43

在 Chrome 游览器中成功运行 jQDemos 页面

1.7 安装和生成 emlab 数据库
①第一种方法:将数据库备份文件 emlab64.bak 复制到 d:\myjsp 文件夹下;打开 SQL Server2008,输入下列命令,从备份中恢复数据库: use master if (db_id('emlab') is not null) drop database emlab restore database emlab from disk='d:\myjsp\emlab64.bak' with replace 此方法只适用于Win7+64位操作系统。Win7+32位操作系统的数据库备份文件为emlab32.bak, 数据恢复命令与上面相同。 ②第二种方法:打开 d:\myjsp\jQDemos\WebRoot\文件夹下的一个子文件夹 sqlscript,在 SQL Server2008 数据库系统中执行这个文件夹下的所有.sql 脚本文件(如图 1-44 所示) 。注意必须先运 行 emlab.sql,创建所有数据表结构,然后关闭这个文件。这时,数据表结构已经存在,但是没有 记录的空表,执行其他脚本文件可生成模拟数据。emlab.sql 只能执行一次,如果再次执行,其他 脚本文件生成的模拟数据会被删除,又需要重新运行这些脚本文件。

图 1-44

emlab 数据库脚本文件清单

- 19 -

《软件开发工具(jQuery) 》实例教程

1.8 SQL Server2008 的网络配置
①执行 Microsoft SQL Sever2008 菜单下的配置工具中找到“SQL Server 配置管理器”(如图 1-45 所示) ,点击该菜单。

图 1-45

找到 SQLServer 数据库配置管理器

②展开菜单树,选中“MSSQLSERVER 的协议”(位于图 1-46 左侧) ,点击图 1-46 右侧的 “TCP/IP”选项。

图 1-46

配置 MSSQLSERVER 协议中的 TCP/IP 选项

- 20 -

《软件开发工具(jQuery) 》实例教程 ③在下图左侧的“协议”栏目中,将“TCP/IP”的“已启用”状态设置为“是”,然后在图 1-47 右侧 的“IP 地址”栏目中,将第一个 IP1 和最后一个 IPALL 中的 TCP 端口值都设置成“1433”。点击“确 定”按钮后返回到前一个窗口界面。

图 1-47

配置 MSSQLSERVER 协议中的 TCP 端口号

④点击下图 1-48 所示的屏幕左侧菜单树中的“SQL Server 服务”,在该图屏幕的右侧中找到 SQL Server(MSSQLSERVER 或 SQLEXPRESS) ,并双击该菜单。

图 1-48

查找 MSSQLSERVER 服务

⑤这时,在下图 1-49 所示的屏幕中点击“重新启动”按钮,数据库服务被重新启动。启动结束 后,返回至上一界面,这时显示 SQL Server(MSSQLSERVER)正在运行。至此在 J2EE 中数据 库配置结束。

- 21 -

《软件开发工具(jQuery) 》实例教程

图 1-49 重新启动 MSSQLSERVER 服务

⑥打开游览器,在地址栏中输入:http://127.0.0.1:8080/jQDemos/。这时程序开始运行,如果 出现下列界面(如图 1-50 所示) ,则表明 J2EE 已成功连接到 SQL Server 数据库 emlab。至此数据 库连接和配置成功,J2EE 全部安装完毕!

图 1-50

MSSQLSERVER 数据库配置连成功

- 22 -

《软件开发工具(jQuery) 》实例教程

第 2 章、EasyUI 基本表单控件
实例 1. 创建 EasyUI 表单及常用控件。
本例创建一个包含jQuery插件的jsp文件,阐述jQuery的页面程序的基本结构。该页面包含一个 EasyUI的表单控件、四个textbox文本框、一个combobox组合框和两个linkbutton按钮控件。页面布 局使用基本的HTML表格( Table)标签。页面程序在 <head>…</head> 之间使用 <script>标签引用 jQuery的几个样式文件和jQuery.min.js、 jQuery.EasyUI.min.js、 EasyUI-lang-zh_CN.js三个插件库文件。 本实例程序运行界面如图2-1所示,完整程序代码见程序2-1。

图2-1

EasyUI表单及常用控件程序运行界面

程序2-1. example01_formbasic.jsp
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <!doctype html> <html lang="en"> <style type="text/css"> </style> <head> <meta charset="utf-8"> <link rel="stylesheet" type="text/css" href="jqEasyUI/themes/default/EasyUI.me.css"> <link rel="stylesheet" type="text/css" href="jqEasyUI/themes/icon.css"> <link rel="stylesheet" type="text/css" href="system/css/icon.css"> <script type="text/javascript" src="jqEasyUI/jQuery.min.js"></script> <script type="text/javascript" src="jqEasyUI/jQuery.EasyUI.min.js"></script> <script type="text/javascript" src="jqEasyUI/EasyUI-lang-zh_CN.js"></script> <script type="text/javascript" src="system/Easyui_functions.js"></script> </head> <body> <h4>EasyUI表单控件基础</h4> <div class="EasyUI-panel" title="注册" style="width:300px"> <div style="padding:10px 10px 10px 30px"> <form id="form1" method="post"> <table cellpadding="5"> <tr>
- 23 -

《软件开发工具(jQuery) 》实例教程
<td>姓名:</td> <td><input class="EasyUI-textbox" type="text" name="name" data-options="required:true"></input></td> </tr> <tr> <td>Email:</td> <td><input class="EasyUI-textbox" type="text" name="email" data-options="required:true,validType:'email'"></input></td> </tr> <tr> <td>课程:</td> <td><input class="EasyUI-textbox" type="text" name="subject" data-options="required:true"></input></td> </tr> <tr> <td>备注:</td> <td><input class="EasyUI-textbox" name="message" data-options="multiline:true" style="height:60px"></input></td> </tr> <tr> <td>语言:</td> <td> <select class="EasyUI-combobox" name="language"> <option value="cn">中文</option> <option value="uk">英文</option> <option value="jp">日文</option> </select> </td> </tr> </table> </form> <div style="text-align:center;padding:5px"> <a href="javascript:void(0)" class="EasyUI-linkbutton" style="width:60px;" onclick="submitForm()">提交</a> <a href="javascript:void(0)" class="EasyUI-linkbutton" style="width:60px;" onclick="clearForm()">清空</a> </div> </div> </div> <script> function submitForm(){ $('#form1').form('submit'); //jQuery语句 } function clearForm(){ $('#form1').form('clear'); //jQuery语句 } </script> </body> </html>
- 24 -

《软件开发工具(jQuery) 》实例教程 主要知识点: ①jQuery+EasyUI插件库的引用及页面文件的总体结构。 ②EasyUI控件在HTML中的定义及其class类的名称。 ③样式CSS、层DIV的使用及利用表格Table进行页面布局(HTML知识点)。 ④EasyUI表单控件中data-options和style选项的设置。例如:data-options="required:true"表示该 输入项值不能为空,validType:'email'表示输入项内容必须符合email的基本格式要求。 ⑤jQquery控件的表达方式:$('#form1') 。 思考题: ①如何设置各个控件的宽度、高度等属性。 ②如何设置组合框combobox的选项与组合框的高度。 ③如何不使用table进行页面布局。

实例 2. EasyUI 表单及其控件的 jQuery 语句设计。
本例利用HTML语句定义一个EasyUI表单控件myForm1,在这个表单中添加多种EasyUI类型控 件,其中包括textbox、numberbox、datebox、combobox等。jQuery程序代码在<scipt>…</scipt>之间 定义,从$(document).ready(function(){});语句开始。 在本例中,表单及控件的高度、宽度等属性的设置均根据EasyUI规则由jQuery语句定义,而控 件在页面中的位置布局则通过HTML的层<div>和<p>标记实现。 关于EasyUI控件的属性将在以后实 例 中 详 细 阐 述 , 详 细 资 料 可 参 见 http://www.jEasyUI.com/documentation/index.php 、 http://www.jEasyUI.com、和中文的 http://www.jEasyUI.net/等网址。本实例程序运行界面如图 2-2所 示,完整程序代码见程序2-2。

图2-2

EasyUI表单及其控件的jQuery程序运行界面

- 25 -

《软件开发工具(jQuery) 》实例教程 程序2-2:example02_formcontrols.jsp
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <html> <style type="text/css"> </style> <head> <meta charset="utf-8"> <link rel="stylesheet" type="text/css" href="jqEasyUI/themes/default/EasyUI.me.css"> <link rel="stylesheet" type="text/css" href="jqEasyUI/themes/icon.css"> <link rel="stylesheet" type="text/css" href="system/css/icon.css"> <script type="text/javascript" src="jqEasyUI/jQuery.min.js"></script> <script type="text/javascript" src="jqEasyUI/jQuery.EasyUI.min.js"></script> <script type="text/javascript" src="jqEasyUI/EasyUI-lang-zh_CN.js"></script> <script type="text/javascript" src="system/Easyui_functions.js"></script> </head> <body style="margin: 2px 2px 2px 2px;"> <div id='main' style="margin:2px 2px 2px 2px;"> <div class="EasyUI-panel" id="myForm1" title="&nbsp;学生信息编辑" style="background:#fafafa;" data-options="iconCls:'panelIcon'" > <fieldset id="myFieldset1" style="position:relative; top:10px; left:10px; width:300px; height:230px; padding: 2px 0px 0px 16px; border:1px groove" > <legend>基本信息</legend> <p>学号:<input class="EasyUI-textbox" type="text" id="stuid" style="padding:0px 2px 0px 4px"></input></p> <p>姓名:<input class="EasyUI-textbox" type="text" id="stuname" style="padding:0px 2px 0px 4px"></input></p> <p>拼音:<input class="EasyUI-textbox" type="text" id="pycode" style="padding:0px 2px 0px 4px"></input> </p> <p>性别:<input class="EasyUI-combobox" type="text" id="gender" style="padding:0px 2px 0px 4px"></input> </p> <p>出生日期:<input class="EasyUI-datebox" type="text" id="birthdate" style="padding:0px 2px 0px 4px"></input> </p> <p>体重:<input class="EasyUI-numberbox" type="text" id="weight" style="padding:0px 2px 0px 4px;"></input> </p> </fieldset> <fieldset id="myFieldset2" style="position:relative; top:20px; left:10px; width:300px; height:200px; padding: 2px 0px 0px 16px; border:1px groove" > <legend>通信信息</legend> <p>家庭地址:<input class="EasyUI-textbox" type="text" id="address" style="padding:0px 2px 0px 4px"></input></p> <p>手机号码:<input class="EasyUI-textbox" type="text" id="mobile" style="padding:0px 2px 0px 4px"></input></p> <p> 家 庭 电 话 : <input class="EasyUI-textbox" type="text" id="homephone" style="padding:0px 2px 0px 4px"></input> </p> <p>Email:<input class="EasyUI-textbox" type="text" id="email" style="padding:0px 2px 0px 4px"></input> </p> <p>微信号:<input class="EasyUI-textbox" type="text" id="weixin"
- 26 -

《软件开发工具(jQuery) 》实例教程
style="padding:0px 2px 0px 4px"></input> </p> </fieldset> </div> </div> <script> $(document).ready(function(){ //jQuery从此代码开始 //example02_formcontrols.jsp var gendersource=[{'gender':'男'},{'gender':'女'}]; $("#myForm1").panel({width:345, height:505}); $("#stuid").textbox({width:120}); $("#birthdate").datebox({width:120}); $("#weight").numberbox({width:120}); $("#gender").combobox({width:120, data:gendersource, valueField:'gender', textField:'gender'}); var items = $('#gender').combobox('getData'); $("#gender").combobox('select', items[0].gender); $("#stuid").textbox('setValue','20143305001'); $("#stuname").textbox('setValue','诸葛亮'); $("#birthdate").datebox('setValue','2015-9-10'); $("#weight").numberbox({precision:1, max:200, min:30}); $("#weight").numberbox('setValue',65.5); $("#weight").numberbox('textbox').css('text-align','right'); }); </script> </body> </html> //jQuery代码从此结束

主要知识点: ①表单常用控件的基本类型:textbox、numberbox、datebox、combobox、checkbox、tabs、tree、 grid、treegrid、filebox、button、menu等。 ②利用jQuery语句设置textbox、datebox、numberbox、combobox的属性,包括宽度、高度等。 例如:$("#stuid").textbox({width:120}); ③利用jQuery语句设置控件的初值。例如:$("#stuname").textbox('setValue','诸葛亮'); ④利用jQuery语句设置numberbox数值框的属性,包括最大值、最小值、小数点位数等。例如: $("#weight").numberbox({precision:1, max:200, min:30}); ⑤利用jQuery语句设置numberbox数值框的右对齐。例如: $("#weight").numberbox('textbox').css('text-align','right'); ⑥利用jQuery语句设置combobox组合框的选项与初值。例如: var gendersource=[{'gender':'男'},{'gender':'女'}]; //定义数据源 $("#gender").combobox({width:120, data:gendersource, valueField:'gender', textField:'gender'}); var items = $('#gender').combobox('getData'); //提取所有选项 $("#gender").combobox('select', items[0].gender); //将初值设置为第一个选项 ⑦datebox控件的日期格式及本地化设置。引入jqEasyUI/EasyUI-lang-zh_CN.js。 ⑧HTML中Fieldset的定义与使用。 ⑨jQuery判断控件是否存在方法: if ($('#id').length>0)

- 27 -

《软件开发工具(jQuery) 》实例教程 思考题: ①不同控件在页面中的上下对齐问题,即如何设置文字与编辑框之间的距离。 ②在页面中一行显示多列问题。例如:如何在“体重”文本框的右侧显示“KG”这个字符。

实例 3. 利用绝对坐标实现表单控件的位置布局。
本例采用绝对(坐标)地址法(position: absolute)确定控件在页面中的显示位置。在EasyUI 中,控件绝对位置的设置采用top和left两个属性(标签),而与其他有些插件使用y和x有所不同。 控件位置属性可以在 HTML的 style 中设置,也可以通过样式 CSS 设置。本例通过 jQuery语句设置 EasyUI控件的位置、尺寸等属性。在EasyUI中,由于有些控件无法直接使用CSS布局定位,这时可 在其外面先添加一个层<div>,然后再对层进行绝对位置布局,以确定控件显示的位置。 本例将实例2中定义位置布局的<p>…</p>换成>div>…</div>,将EasyUI-panel类型的外层容器 myForm1的position设置为relative(在style中设置) ,在这个容器内添加的控件其style中的position设 为absolute。每个控件及其label采用jQuery代码设置,所有label实现右对齐。 本实例程序运行界面如图2-3所示,主要代码如下见程序2-3。

图2-3. 利用绝对坐标实现表单控件位置布局程序运行界面

程序2-3. example03_absolutelayout.jsp
<body style="margin: 2px 2px 2px 2px;"> <div id="main" style="margin:2px 2px 2px 2px;"> <div class="EasyUI-panel" id="myForm1" title="&nbsp;学生信息编辑" style="position:relative; background:#fafafa;" data-options="iconCls:'panelIcon'" > <fieldset id="myFieldset1" style="position:absolute; top:10px; left:10px; width:300px; height:210px; padding: 2px 0px 0px 16px; border:1px groove" > <legend>基本信息</legend> <label id='stuid_label'>学号:</label> <div id="stuid_div"><input class="EasyUI-textbox" type="text" id="stuid"></input></div> <label id='stuname_label'>姓名:</label> <div id="stuname_div"><input class="EasyUI-textbox" type="text" id="stuname"></input></div> - 28 -

《软件开发工具(jQuery) 》实例教程
<label id='pycode_label'>拼音:</label> <div id="pycode_div"><input class="EasyUI-textbox" type="text" id="pycode"></input></div> <label id='gender_label'>性别:</label> <div id="gender_div"><input class="EasyUI-combobox" type="text" id="gender"></input></div> <label id='birthdate_label'>出生日期:</label> <div id="birthdate_div"><input class="EasyUI-datebox" type="text" id="birthdate"></input></div> <label id='weight_label'>体重:</label> <div id="weight_div"><input class="EasyUI-textbox" type="text" id="weight"></input></div> <label id='weightx_label'>KG</label> </fieldset> <fieldset id="myFieldset2" style="position:absolute; top:235px; left:10px; width:300px; height:180px; padding: 2px 0px 0px 16px; border:1px groove" > <legend>通信信息</legend> <label id='address_label'>家庭地址:</label> <div id="address_div"><input class="EasyUI-textbox" type="text" id="address" style="padding:0px 2px 0px 4px"></input></div> <label id='mobile_label'>手机号码:</label> <div id="mobile_div"><input class="EasyUI-textbox" type="text" id="mobile" style="padding:0px 2px 0px 4px"></input></div> <label id='homephone_label'>家庭电话:</label> <div id="homephone_div"><input class="EasyUI-textbox" type="text" id="homephone" style="padding:0px 2px 0px 4px"></input></div> <label id='email_label'>Email:</label> <div id="email_div"><input class="EasyUI-textbox" type="text" id="email" style="padding:0px 2px 0px 4px"></input></div> <label id='weixin_label'>微信号:</label> <div id="weixin_div"><input class="EasyUI-textbox" type="text" id="weixin" style="padding:0px 2px 0px 4px"></input></div> </fieldset> </div> </div> <script> $(document).ready(function(){ //控件位置布局 $("#stuid_label").css({position: "absolute", top:"23px", left:"10px", width:"65px", "text-align":"right", "z-index":2}); $("#stuid_div").css({position: "absolute", top:"20px", left:"76px", "z-index":2}); $("#stuname_label").css({position: "absolute", top:"53px", left:"10px", width:"65px", "text-align":"right", "z-index":2}); $("#stuname_div").css({position: "absolute", top:"50px", left:"76px","z-index":2}); $("#pycode_label").css({position: "absolute", top:"83px", left:"10px", width:"65px", "text-align":"right", "z-index":2}); $("#pycode_div").css({position: "absolute", top:"80px", left:"76px", "z-index":2}); $("#gender_label").css({position: "absolute", top:"113px", left:"10px", width:"65px", "text-align":"right", "z-index":2}); $("#gender_div").css({position: "absolute", top:"110px", left:"76px", "z-index":2}); $("#birthdate_label").css({position: "absolute", top:"143px", left:"10px", width:"65px", "text-align":"right", "z-index":2}); $("#birthdate_div").css({position: "absolute", top:"140px", left:"76px", "z-index":2}); $("#weight_label").css({position: "absolute", top:"173px", left:"10px", width:"65px", text-align":"right", "z-index":2}); $("#weight_div").css({position: "absolute", top:"170px", left:"76px", "z-index":2}); $("#weightx_label").css({position: "absolute", top:"173px", left:"190px", width:"25px", "text-align":"right", "z-index":2}); $("#address_label").css({position: "absolute", top:"23px", left:"10px", width:"65px", - 29 -

《软件开发工具(jQuery) 》实例教程
"text-align":"right", "z-index":2}); $("#address_div").css({position: "absolute", top:"20px", left:"76px", "z-index":2}); $("#mobile_label").css({position: "absolute", top:"53px", left:"10px", width:"65px", "text-align":"right", "z-index":2}); $("#mobile_div").css({position: "absolute", top:"50px", left:"76px", "z-index":2}); $("#homephone_label").css({position: "absolute", top:"83px", left:"10px", width:"65px", "text-align":"right", "z-index":2}); $("#homephone_div").css({position: "absolute", top:"80px", left:"76px", "z-index":2}); $("#email_label").css({position: "absolute", top:"113px", left:"10px", width:"65px", "text-align":"right", "z-index":2}); $("#email_div").css({position: "absolute", top:"110px", left:"76px", "z-index":2}); $("#weixin_label").css({position: "absolute", top:"143px", left:"10px", width:"65px", "text-align":"right", "z-index":2}); $("#weixin_div").css({position: "absolute", top:"140px", left:"76px", "z-index":2}); $("#myForm1").panel({width:345, height:465}); $("#stuid").textbox({width:120}); $("#birthdate").datebox({width:120}); $("#weight").numberbox({width:120}); $("#stuid").textbox('setValue','20143305001'); $("#stuname").textbox('setValue','诸葛亮'); $("#birthdate").datebox('setValue','2015-9-10'); $("#weight").numberbox({precision:1, max:200, min:30}); $("#weight").numberbox('setValue',65.5); $("#weight").numberbox('textbox').css('text-align','right'); //设置combobox var gendersource=[{'gender':'男'},{'gender':'女'}]; $("#gender").combobox({width:120, data:gendersource, valueField:'gender', textField:'gender'}); var items = $('#gender').combobox('getData'); $("#gender").combobox('select', items[0].gender); $("#address").textbox({width:230}); }); </script> </body>

主要知识点: ①在 EasyUI 中绝对坐标定位采用 top 和 left 属性,而不是有些插件库中使用 y 和 x。 ②数字框 numberbox 右对齐方式$("#weight").numberbox('textbox').css('text-align','right')。 ③label 标签和编辑型控件的 CSS 设置,设置其 top、left、width 等属性值,当然还有 position 值为 absolute。 思考题: 1.如果在 jQuery 中不定义控件的 CSS,页面显示的效果会怎样? 2.控件(包括一些如 fieldset 之类的容器)采用绝对坐标的定位显示方式虽然效果较好,但 程序书写比较繁琐,如何简化? 3.如何动态定义页面中的控件?即不在 HTML 中事先定义控件,而在<script>…</script>之 间使用 jQuery 语句定义。 作业题: 使用EasyUI插件及绝对地址定位方式,编写程序设计图2-4所示页面。

- 30 -

《软件开发工具(jQuery) 》实例教程

图 2-4

使用绝对坐标定位作业题效果图

实例 4. 利用 append()方法在 jQuery 中动态定义和生成 EasyUI 控件。
前面几个实例采用HTML标签语句定义控件,但有时也有一些控件由于事先是不确定的,需要 在程序运行过程中动态生成,为此本例介绍append()方法,在javascript语句中动态定义EasyUI控件, 具体方法和程序如下。 ①在页面预留一个层,取名为main。所有其他动态生成的控件均嵌套在这个层之内。 <div id="main" style="margin:2px 2px 2px 2px;"> ②在<script>…</script>之间编写程序。先定义一个变量(如str),把需要生成控件的HTML语 句保存到这个变量中,然后使用append()方法添加到相应的父类容器中去。 例如,在main层中添加一个表单类(panel)控件的语句如下: var str='<div class="EasyUI-panel" id="myForm1" title="&nbsp;学生信息编辑" style="position:relative; background:#fafafa;" data-options="iconCls:\'panelIcon\'" >'; $("#main").append($(str)); //在main容器下嵌入一个表单控件myForm1 同样地,在表单myForm1中添加一个fieldset类控件的语句如下: str='<fieldset id="myFieldset1" style="position:absolute; top:10px; left:10px; width:300px; height:210px; padding: 2px 0px 0px 16px; border:1px groove" ><legend>基本信息</legend></fieldset>'; $("#myForm1").append($(str)); //在myForm1容器下嵌入一个fieldset字段集控件 推而广之,各类控件都可以通过这种方式动态生成。又如在myFieldset1字段集容器中添加两个 label和textbox文本框控件,其语句如下:
str='<label id="stuid_label">学号:</label>'; str+='<div id="stuid_div"><input class="EasyUI-textbox" type="text" id="stuid"></input></div>\n'; str+='<label id="stuname_label">姓名:</label><div id="stuname_div"><input class="EasyUI-textbox" type="text" id="stuname"></input></div>\n'; $("#myFieldset1").append($(str));

③与实例3相同,在动态添加和生成控件之后,可以使用jQuery语句设置各个控件的属性。 本例完整代码见程序example04_appendcontrols.jsp中。 主要知识点: 动态添加控件的方法:$("#parentid").append($(str));。这里,parentid 为父类容器的 ID,str 变 量为符合 HTML 语法的控件定义语句,str 需要用括号和$引导。

- 31 -

《软件开发工具(jQuery) 》实例教程 思考题: 1.在动态定义各个控件时,有哪些代码具有相似性或重复性?如何使用函数动态定义控件? 2.构造一个函数用于动态定义textbox控件,这个函数需要几个参数?参考下列API链接地址, 查看相关控件的属性。 http://www.jEasyUI.com/demo/main/ http://www.jEasyUI.com/documentation/index.php

实例 5. 构造控件自定义函数,简化控件的使用。
从前面实例中可以看出控件的定义是比较繁琐的,如果将一些常用的控件通过函数形式加以 定义和调用,这将大大简化控件的使用。函数可以将控件的许多标准属性加以固化,同时又允许 用户自己定义一些属性,这些属性往往可被描述为参数。 jQDemos 工程创建一个名为 fn_function.js 的 javascript 公共文件,该文件中包含各类控件自 定义函数,并在以后实例中调用这些函数。这里仅介绍表单 panel、字段集容器 fieldset、文本框 textbox 这三个控件的定义函数。 ①myForm()函数:定义一个表单,其参数包括 id、parent、title、top、left、height、width 和 style 等,分别表示控件标识符、父类容器名、窗体标题、起始显示位置坐标、表单的高度和宽度、 表单样式,style 参数选项指定表单是否可以最大化、最小化、收缩或关闭。 ②myFieldset()函数。 定义一个容器, 在容器内分组显示各个字段, 其参数包括 id、 parent、 title、 top、left、height、width 等,各参数的含义与 myForm()类同。 ③myTextField()函数。 定义一个 textbox 文本输入框, 其参数包括 id、 parent、 label、 labelwidth、 top、left、height、width、value、style 等。这里 label 为文本输入框之前的提示符,labelwidth 为 该提示符的宽度,value 为文本框的初值,style 为文本框的数据验证方式,包括 readonly(只读) 、 email(邮件格式验证) 、url(网址格式验证) 、password(密码形式隐藏) 、icon(图标显示)等。 控件自定义函数的引用方式与其他插件库 JS 文件相同,即在<head>…</head>之间添加下列 代码:<script type="text/javascript" src="system/Easyui_function.js"></script>。jQDemos 控件自定义 函数的主要参数如表 2-1 所示。
表 2-1. 控件自定义函数主要参数表 参数 id parent title top left height width label labelwidth value 控件标识符 父类容器的标识符 说明 max items 参数 说明 数字框输入数据的最大值 静态 combobox、checkbox、menu 等控 件的可选项,各选项之间用分号分隔 静态 combobox、checkbox、menu 等控 件的可选项,各选项之间用分号分隔 checkbox 等控件中选项分行显示时的行 高(行间距) checkbox 等控件中每行显示的选项个数 (即列数) 动态 combobox 控件中选项文本列名称 多个 combobox 控件联动时依赖于主组 合框的列名称 数据表的关键字 (通常为主键) , 用于与 数据库连接的控件 数据表的排序列(缺省时为 keyfield 的 值) ,用于与数据库连接的控件 动态 combobox、grid、tree 等控件从数 据库中提取数据的查询语句

标题(用于表单、标签页、树、数据网格 cols 等控件中) 控件在屏幕上显示位置的 Y 坐标值 控件在屏幕上显示位置的 X 坐标值 控件的高度 控件的宽度 编辑型控件输入引导提示符的标签名 引导提示符标签的宽度 文本框等控件的初值 textfield masterfield keyfield sortfield sql buttons tabs

- 32 -

《软件开发工具(jQuery) 》实例教程
length decimal min 输入数据的最大长度(字符数) 数字框的小数位数 数字框输入数据的最小值 style 定义 window 弹出式窗体控件的按钮, 为 ok、cancel、save 的组合 分页标签控件中各个分页的标题,用分 号分隔 其他属性的选项值(包括最大化、最小 化、收缩、关闭等)

下面以 myTextField 为例,阐述控件自定义函数的主要设计步骤。 ①熟悉和掌握控件的常用属性,确定哪些属性是固定的、哪些是可变的(可设置的) ;把可变 的属性定义为参数。为此确定 textbox 的主要参数为 id, parent, label, labelwidth, top, left, height, width, value, style 等。
function myDefineTextField(id, parent, label, labelwidth, top, left, height, width, value, style){

②默认值设置。例如:如果父类容器标识符为空,则设置为 main,文本框的高度位 0,则设 置为系统默认值(这里由 systext.height 变量给定,默认值为 24px) 。
if (parent=='') parent='main'; if (height==0) height=systext.height;

③根据参数 label 的值,确定是否需要创建一个输入提示符 label 文字标签。当 label 参数值为 非空时,调用 myFieldLabel()创建一个文字标签。如果 labelwidth 为 0 时,文字标签与文本编辑框 分行显示。
if (label!='' && labelwidth==0){ myFieldLabel(id,parent,label,labelwidth,top,left+2); //创建文字标签 top=1*(top+syslabel.fontsize+syslabel.topmargin+2); //换行显示文本框 labelwidth=0; }else{ myFieldLabel(id,parent,label,labelwidth,top,left); //创建文字标签 } }

④创建文本框控件,需要在其外面添加一个层(这个层也有 id) ,以帮助确定其绝对位置。 创建文本框的 HTML 语句保存在一个变量 (str) 中。 如果文本框的初值参数 value 非空, 则在 HTML 定义中添加初值设置。之后使用 append 语句将控件添加到父类容器中去。
var str='<div id="'+id+'_div"><input '; if (value!=undefined && value!=''){ //设置初值 str+=' value="'+value+'"'; } str+=' class="EasyUI-validatebox EasyUI-textbox" type="text" id="'+id+'" style="padding:0px 6px 0px 6px;" ></div>'; $("#"+parent).append($(str));

④创建控件之后,根据函数中的参数值,设置控件的相关属性。控件位置等属性在层<div> 的样式 CSS 中设置,这里通过调用 myTextCss()函数实现。控件的高度在 textbox({height:?})设置。
$("#"+id+'_div').css(myTextCss(top,1*(left+labelwidth),height,width)); $("#"+id).css({height:"100%", width:"100%"}); $("#"+id).textbox({height: height});

⑤设置文本框的其他自定义属性(如 xparent、xid、xlabel 等) ,这些属性不是 EasyUI 本身拥 有的,而是为了程序设计方便,程序员自己添加的。
$("#"+id).attr('xparent',parent); $("#"+id).attr('xlabel',label); $("#"+id).attr('xid',id); //自定义属性,父类容器的标识符 //自定义属性,输入提示符

//自定义属性,控件本身的标识符
- 33 -

《软件开发工具(jQuery) 》实例教程 ⑥根据 style 参数值设置控件的其他属性,例如:控件是否只读,是否按 email 格式、url 格式 验证数据。如果 style 中包含 password 字符,则文本框按密码形式输入。这项功能通过调用 myFieldStyle()函数实现,即:myFieldStyle(id,style); myTextField()函数应用举例:
myDefineTextField('email','myFieldset1','Email:', 70, 20, 12, 0, 180, 'zxywolf@163.com', 'email'); myDefineTextField('psw','myFieldset1','密码:', 70, 55, 12, 0, 180, '888, 'password'); myDefineTextField('pycode','myFieldset1','姓名拼音:', 70, 55, 12, 0, 180, ' ', 'readonly');

下面给出 myTextField()、myFieldLabel()、myTextCss()、myFieldStyle()这四个函数的完整程 序代码: 程序 2-5-1:文本框定义函数 myTextField()
function myTextField(id,parent,label,labelwidth,top,left,height,width,value,style){ var str=''; if (parent=='') parent='main'; if (height==0) height=systext.height; if (labelwidth==0 && label!=''){ myFieldLabel(id,parent,label,labelwidth,top,left+2); top=1*(top+syslabel.fontsize+syslabel.topmargin+2); //换行显示文本 labelwidth=0; }else{ myFieldLabel(id,parent,label,labelwidth,top,left); } str+='<div id="'+id+'_div"><input '; if (value!=undefined && value!=''){ //设置初值 str+=' value="'+value+'"'; } str+=' class="easyui-validatebox easyui-textbox" type="text" id="'+id+'" style="padding:0px 6px 0px 6px;" ></div>'; $("#"+parent).append($(str)); $("#"+id+'_div').css(myTextCss(top,1*(left+labelwidth),height,width)); $("#"+id).css({height:"100%", width:"100%"}); $("#"+id).textbox({height: height}); $("#"+id).attr('xparent',parent); //自定义属性,父类容器的标识符 $("#"+id).attr('xlabel',label); //自定义属性,输入提示符 $("#"+id).attr('xid',id); //自定义属性,控件本身的标识符 myFieldStyle(id,style); }

程序2-5-2:控件中的文字标签label子定义函数myFieldLabel()
function myFieldLabel(id,parent,label,labelwidth,top,left){ //定义控件中的label if (label!=undefined && label!=''){ $("#"+parent).append("<label id='label"+id+"' align='"+syslabel.align+"'>"+label+"</label>"); if (labelwidth>0){ $("#label"+id).css(myLabelCss(top+syslabel.topmargin,left,0,labelwidth)); }else{ $("#label"+id).css(myLabelCss(top,1*left+2,0,label.length*syslabel.fontsize)); top=1*(top+syslabel.fontsize+syslabel.topmargin); //换行显示文本 } }else labelwidth=0; }

- 34 -

《软件开发工具(jQuery) 》实例教程 程序 2-5-3:文本框控件样式 CSS 子定义函数 myTextCss()
function myTextCss(top,left,height,width){ var str=''; var css=''; if (top!=undefined && left!=undefined){ str='var css={padding:"0px 2px 0px 4px", position: "absolute", top:"'+top+'px", left:"'+left+'px"'; if (width!=undefined && width>0){ str+=', width: '+width; } if (height!=undefined && height>0){ str+=', height: '+height; } str+=', "z-index":2};\n'; }else{ str+="\n"; } eval(str); //console.log(str); return css; }

程序 2-5-4:文本框其他属性特征自定义函数 myFieldStyle
function myFieldStyle(id,style){ //设置style只读、图标 if (style!=undefined && style!=''){ var tmp=(style+';').split(';'); for (var i=0;i<tmp.length;i++){ //console.log(tmp[i]); if (tmp[i]=='readonly') $("#"+id).textbox({readonly: true}); if (tmp[i]=='email') $("#"+id).textbox({validType:'email'}); if (tmp[i]=='url') $("#"+id).textbox({validType:'url'}); if (tmp[i]=='password') $("#"+id).textbox({type:'password'}); if (tmp[i].indexOf('icon:')>=0){ var x1=tmp[i].indexOf('icon:'); var x2=tmp[i].indexOf(';',x1+1); if (x1>=0 && x2>0) var icon=tmp[i].substring(x1+5,x2-1); else var icon=tmp[i].substr(x1+5,255); //$("#"+id).textbox({iconCls: icon}); // $("#"+id).textbox({buttonIcon: icon}); } } } }

相关知识点: ①string.split函数:将一个字符串按某个分隔符进行分割后,将分隔的各个值存储到一个数组 变量中。例如: var xfields="stuid;stuname;gender;birthdate;address"; var tmp=xfields.split(';'); 这是将xfields中的字符按分号(;)去分割,之后得到5个字符串,存放到数组tmp中。 ②eval()函数:可计算某个字符串,并执行其中的 JavaScript 代码。例如:
- 35 -

《软件开发工具(jQuery) 》实例教程 eval("var x=100; var y=x+10;"); 命令执行后,得到 x 和 y 两个变量,其值分别为 100 和 110。又如: var data='{stuid:"2014540101", name:"贾宝玉"}'; eval("var source="+data); alert(source.name); 命令执行后,在屏幕上显示“贾宝玉”这个字符串。

实例 6. 控件定义函数的综合应用。
本例利用控件自定义函数,创建一个表单和四个 fieldset 控件,在每个 fieldset 中添加若干个 textbox、datebox、numberbox、checkbox、combobox、filebox 等控件。与实例 3 相比,采用这种 方式定义控件,可以大大减少程序代码量,增强了程序的可读性。对于一些在函数中没有涉及到 的控件属性和控件事件,可以在引用自定义函数定义之后单独编写代码实现。例如本例为学生文 本框添加了两个属性和一个 onChange 事件。 在后续实例中,为了节省篇幅,一般控件的定义将主要采用这种函数的形式。本实例程序运 行界面如图 2-6 所示,完整程序代码见程序 2-6。

图 2-5

利用控件自定义函数的程序运行界面

程序 2-6:example06_functionapp.jsp
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <html> <style type="text/css"> </style> <head> <meta charset="utf-8"> <link rel="stylesheet" type="text/css" href="jqEasyUI/themes/default/EasyUI.me.css"> <link rel="stylesheet" type="text/css" href="jqEasyUI/themes/icon.css"> <link rel="stylesheet" type="text/css" href="system/css/icon.css"> <script type="text/javascript" src="jqEasyUI/jQuery.min.js"></script> - 36 -

《软件开发工具(jQuery) 》实例教程
<script type="text/javascript" src="jqEasyUI/jQuery.EasyUI.min.js"></script> <script type="text/javascript" src="jqEasyUI/EasyUI-lang-zh_CN.js"></script> <script type="text/javascript" src="system/Easyui_functions.js"></script> </head> <body style="margin: 2px 2px 2px 2px;"> <div id="main" style="margin:2px 2px 2px 2px;"> </div> <script> $(document).ready(function(){ //定义 EasyUI-panel 容器控件 myForm('myForm1','main','学生信息编辑',0,0,490,695,'close;collapse;min;max'); myFieldset('myFieldset1','myForm1','基本信息',010,10,230,290); myFieldset('myFieldset2','myForm1','通信信息',010,320,230,350); myFieldset('myFieldset3','myForm1','个人特长',250,10,200,290); myFieldset('myFieldset4','myForm1','上传照片',250,320,200,350); myTextField('stuid','myFieldset1','学号:',70,33*0+20,12,0,120,'D20101'); myTextField('stuname','myFieldset1','姓名:',70,33*1+20,12,0,160,'贾宝玉'); myTextField('pycode','myFieldset1','汉语拼音:',70,33*2+20,12,0,160,''); myDateField('birthdate','myFieldset1','出生日期:',70,33*3+20,12,0,120,'1997-2-17'); myComboField('gender','myFieldset1','性别:',70,33*4+20,12,0,120,'男;女',''); myNumericField('weight','myFieldset1','体重:',70,33*5+20,12,0,120,8,2,'60.25','10','100'); myLabelField('label1', 'myFieldset1','KG',33*5+18+7,220,0,0); myTextField('address','myFieldset2','家庭地址:',70,33*0+20,12,0,255,'浙江省杭州市西湖区'); myTextField('mobile','myFieldset2','手机号码:',70,33*1+20,12,0,180,''); myTextField('homephone','myFieldset2','家庭电话:',70,33*2+20,12,0,180,''); myTextField('email','myFieldset2','Email:',70,33*3+20,12,0,180,'zxywolf@163.com'); myTextField('qq','myFieldset2','QQ 号:',70,33*4+20,12,0,180,'857199052'); myTextField('weixin','myFieldset2','微信号:',70,33*5+20,12,0,180,'zxywolf888'); myCheckBoxField('research','myFieldset3','个人特长:',70,33*0+20,12,24,3, '围棋;国际象棋;足球;长跑;数学;信息技术'); myMemoField('notes','myFieldset3','个人简介:',0,33*2+5,10,100,273,''); myFileField('photo','myFieldset4','',0,26,6,0,240,' '); //定义事件 $("#photoupload").bind('click',function(e){ var targetname=$("#stuid").textbox('getValue'); var result=myFileupLoad('photo','mybase/students/',targetname); console.log(result); }); //为“学生”文本框添加在自定义函数中没有涉及的属性和事件 $("#stuname").textbox({ prompt:"姓名有效长度为 20 个字符", required: true, onChange: function(newv,oldv){ alert("姓名已发生变化,请重新输入拼音"); } }); }); </script> </body> </html>

思考题: 深入分析研究 myCheckBoxField()自定义函数的构造及其应用。
- 37 -

《软件开发工具(jQuery) 》实例教程

实例 7. 使用 tabs 标签页控件分页显示多个表单控件。
EasyUI 的标签页/选项卡(tabs)控件可以将多个表单组合在一起,采用类似于分页的形式显 示信息,其主要属性包括:title、closable、tabPosition、tabWidth、tabHeight 等。标签页通常作为 一种容器加以使用,一般情况可以有多个分页标签同时存在,但是同时只有一个处于激活状态。 本例将实例 6 中四个栏目的学生信息按标签页进行分页显示, 以三种方法创建标签页 myTab。 ①方法 1:在网页的<body>…</body>之间添加下列 HTML 语句,以<div>层嵌套形式实现标 签页,例如下列语句可定义 4 个标签页。
<div id="myTab" class="EasyUI-tabs" style="overflow: auto; margin: 0px 0px -19px 0px; width:390px; height:285px;"> <div id="myTab1" title="基本信息" style="position:relative; overflow:auto;"></div> <div id="myTab2" title="通信信息" style="position:relative; overflow:auto;"></div> <div id="myTab3" title="个人简历" style="position:relative; overflow:auto;"></div> <div id="myTab4" title="上传照片" style="position:relative; overflow:auto;"></div> </div>

②方法 2:在<script>…</script>之间编写 jQuery 程序,例如:
var str='<div id="myTab" class="EasyUI-tabs" style="overflow: auto; margin: 0px 0px -19px 0px; padding 0px 0px 0px 0px;">'; str+='<div id="myTab1" title="基本信息" style="position:relative; overflow:auto;"></div>'; str+='<div id="myTab2" title="通信信息" style="position:relative; overflow:auto;"></div>'; str+='<div id="myTab3" title="个人简历" style="position:relative; overflow:auto;"></div>'; str+='<div id="myTab4" title="上传照片" style="position:relative; overflow:auto;"></div>'; str+='</div>'; $("#main").append($(str)); $("#myTab").tabs({height:285, width:385});

③方法 3:直接调用控件自定义函数 myTabs()。例如调用下列函数可以产生 4 个选项卡的标 签页,其高度为 285 像素,宽度为 385 像素。
myTabs('myTab', 'main', '基本信息;通信信息;个人简历;上传照片', 0, 0, 285, 385, ' ');

在定义 myTab 标签页之后,可以使用$("#myTab").tabs('select', index)方法聚焦(选中)某个 标签页中的选项卡分页,使用 $("#myTab").tabs("tabs").length 获取标签页的选项卡总数,使用 $("#myTab").tabs('update', { tab: $("#myTab").tabs('getTab', 0), options:{} })更新某个选项卡分页。 本 实例程序运行界面如图 2-6 所示。

图2-6 标签页Tabs控件程序运行界面

作业题: 编写 JS 程序,实现 tabs 标签页控件中选项卡分页的动态增加与删除。

- 38 -

《软件开发工具(jQuery) 》实例教程

实例 8. 静态组合框 combobox 控件及其事件和初值的设置。
在EasyUI中,组合框控件(combo或combobox,也称下拉框)需要绑定一个数据源(source) , 以指定其选项的来源。通常,这个数据源可以是本地数据集(静态) ,也可以是远程服务器端符合 规定格式数据集(动态) 。 在定义本地数据源时一般采用JSON格式的数组。例如,有关性别的数据源可以定义如下: var gendersource =[{"gender":"男"},{"gender":"女"}]; 在这个JSON格式数据中,“性别”对应的列名为gender,选项为“男”和“女”两个。也可以采用多 维数组定义组合框数据源。例如,有关城市组合框的数据源可定义如下: var citysource=[{"cityid":"330100", "city":"杭州市"}, {"cityid":"330200", "city":"宁波市"}] 这里,每个城市选项中有两个列:cityid和city。 在定义数据源之后,需要设置组合框控件的相关属性。数据源由data属性指定,组合框显示的 值和组合框返回的值分别由 textField 和 valueField 这两个关键属性指定。当 valueField 缺省时,由 combobox("getValue")返回的值总是为空。 本例在一个表单中定义5个数据源及其相应的组合框控件,并为“学历”组合框和“城市”组合框 分别定义一个onChange事件和onSelect事件。这两个事件在用户改变组合框的选项时都会被触发, 其中onSelect事件可以提取当前选项对应的各个数据源值。 组合框的初值通过combobox('select')或combobox('setValue')两种方法进行设置。 例如, 下列语句 将“学历(degree)”组合框的初值设置为第3个选项值(即“本科”) 。 $('#degree').combobox('select',degreesource[2].degree); 组合框选项初值的赋值语句应当放在控件属性和事件定义之后。 下面给出“城市”组合框的完整 定义过程和方法: ①使用JSON格式定义数据源,存放在一个数组变量citysource中。
var citysource=[{"cityid":"330100","city":"杭州市"},{"cityid":"330200","city":"宁波市 "},{"cityid":"330300","city":"温州市"},{"cityid":"330400","city":"嘉兴市"},{"cityid":"330500","city":"湖州市 "},{"cityid":"330600","city":"绍兴市"},{"cityid":"330700","city":"金华市"},{"cityid":"330800","city":"衢州市 "},{"cityid":"330900","city":"舟山市"},{"cityid":"331000","city":"台州市"},{"cityid":"331100","city":"丽水市"}];

②使用JS代码在$("#myFieldset1")中添加一个组合框控件,并在其style中指定位置和尺寸
$("#myFieldset1").append('<div 6px" /></div>'); style="position: absolute; top:300px; left:87px; width: 100px; padding-left: 4px;" id="city_div"><input class="EasyUI-combobox" id="city" style="padding:0px 6px 0px

③ 设置组合框的 valueField 和 textField 属性属性,使用 data 属性绑定选项数据源 citysource 。 panelHeight为组合框下拉时显示的高度(按像数计算) ,选项较少时,可以为auto值。
$("#city").combobox({ width:160, panelHeight: 120, data: citysource, valueField: 'cityid', }); //getValue组合框中提取出来的值 textField: 'city' //组合框显示的值

④编写组合框onSelect事件。当用户选中组合框的某个选项时,onSelect事件被触发。
$("#city").combobox({ onSelect: function(record) { //选中事件 if (record) {
- 39 -

《软件开发工具(jQuery) 》实例教程
alert(record.city+'---'+record.cityid+'---'+$("#city").combobox('getValue')); } } });

⑤使用select方法设置组合框的初值,也可以用setValue方法设置初值。两者不同之处在于select 方法可以触发onSelect事件,而setValue不会触发事件。
$('#city').combobox('select', citysource[0].city); $('#city').combobox('setValue', citysource[0].city);

从上面代码可以发现,静态组合框的定义也是比较繁琐的。其实,组合框的定义过程也可以 用一个函数实现,下面给出 myComboField()自定义函数的参数及应用示例。
myComboField(id,parent,label,labelwidth,top,left,height,width,items,value,style)

这里,items 为静态组合框的选项,各个选项之间用分号分隔。例如定义一个“职称”组合框:
myComboField('title', 'myFieldset1', '职称:', 70, 300, 16, 0, 120, '教授;副教授;讲师;助教;其它', '副教授', 'autodrop');

这里,“职称”组合框共 5 个选项,其初值为“副教授”。style 参数值 autodrop 表示组合框为非 编辑状态,即点击组合框时就自动弹出其选项下拉框。 myComboField() 函数的具体代码见 Easyui_functions.js 文件。 相对于静态组合框,基于数据库的动态组合框的定义更为复杂些,有关内容将在第 3 章相关 实例中介绍。

实例 9. 利用滑块(slider)控件实现图片的等比例缩放。
滑块(slider)允许用户从一个有限的范围内选择一个数值,当沿着轨道移动滑块控件时,该 控件将显示一个表示当前值的提示框,用户可通过设置它的属性来自定义滑块。可以使用<input> 创建滑块控件,例如: <input class="EasyUI-slider" value="12" style="width:300px" data-options="showTip:true, rule:[0, '|', 25, '|', 50, '|', 75, '|', 100]" > 上面使用<input>方法在CSS中设置滑块的绝对位置是无效的。也可以通过<div> 创建滑块,但 是这时value属性是无效的。这里我们通过<input>创建滑块,在滑块外添加一个层<div>,用来设置 滑块的绝对坐标位置。

图2-7. 利用滑块控件实现图片等比例缩放程序运行界面

- 40 -

《软件开发工具(jQuery) 》实例教程 本例在表单中定义一个HTML图片控件(image1) ,学生学号为一个组合框(combobox) ,每个 学生对应一个图片文件,其文件名为姓名拼音与png文件的组合(如jiabaoyu.jpg) 。当用户在组合框 中选定某个学生时,触发组合框的onSelect事件,这时image1控件中即时显示该学生对应的图片文 件。滑块用于调整图片的大小,图片可以最大放大至100%。resizeImage()函数根据图片原始大小, 等比例计算图片缩放后的宽度和高度,保证图片大小变化过程中不被扭曲。本实例程序运行界面图 2-7所示,其主要程序实现方法与过程如下。 ① 定义表单 myForm1 ,在表单中添加多个控件,其中包括学号对应的组合框数据源数组 studentsource及组合框控件stuid。
var studentsource=[ {"stuid":"D2014540101","stuname":"贾宝玉","pycode":"jiabaoyu","gender":"男", "birthdate":"1996-02-10", "place":"浙江省杭州市"}, {"stuid":"D2014540102","stuname":"林黛玉","pycode":"lindaiyu","gender":"女", "birthdate":"1996-07-15", "place":"浙江省温州市"}, {"stuid":"D2014540103","stuname":"薛宝钗","pycode":"xuebaocha","gender":"女", "birthdate":"1995-12-20", "place":"浙江省绍兴市"} ]; myForm('myForm1','main','学生信息',0,0,315,520,''); myFieldset('myFieldset1','myForm1','基本信息',10,10,240,255); myLabelField('stuid','myFieldset1','学号:',36*0+25,12,0,0); myTextField('stuname','myFieldset1','姓名:',70,36*1+20,12,0,160); myTextField('pycode','myFieldset1','汉语拼音:',70,36*2+20,12,0,160,''); myDateField('birthdate','myFieldset1','出生日期:',70,36*3+20,12,0,120,'1997-2-17'); myComboField('gender','myFieldset1','性别:',70,36*4+20,12,0,120,'男;女',''); myTextField('place','myFieldset1','出生地:',70,36*5+20,12,0,120,8,2,'60.25','10','100'); //定义学生编码对应的组合框 $("#myFieldset1").append('<div style="position: absolute; top:22px; left:82px; width: 100px; padding-left: 4px;" id="stuid_div"><input class="EasyUI-combobox" id="stuid" style="padding:0px 6px 0px 6px" /></div>'); $("#stuid").combobox({ width:160, panelHeight: 'auto', editable: false, data: studentsource, valueField: 'stuid', textField: 'stuid' });

②在表单中定义学生照片图片控件image1和滑块控件slider1,并设置图片的src(文件路径和名 称)值为空,即先暂时不显示图片。
var str='<img id="image1" src=" " style="position: absolute; top:18px; left:285px;"></img>'; str+='<div style="position: absolute; top:230px; left:290px; width:200px;">'; str+='<input id="slider1" class="EasyUI-slider" value="0" ></div>'; $("#myForm1").append($(str)); //定义slider控件 $("#slider1").slider({ showTip: true, min:1, max:100, rule: [0,'|',25,'|',50,'|',75,'|',100], tipFormatter: function(value){ return value; }, });
- 41 -

《软件开发工具(jQuery) 》实例教程 ③ 编 写 滑 块 控 件 的 onChange 事 件 , 即 当 滑 块 在 轨 道 上 移 动 时 , 触 发 该 事 件 , 调 用 函 数 resizeImage(),将滑块当前值value传给函数,以改变学生照片的大小,对图片进行等比例缩放。
$("#slider1").slider({ onChange: function(value){ var src=$("#image1").attr("src"); resizeImage('image1',src,value); } });

④编写学生组合框的onSelect事件,即当组合框中选定某个学生时,从数组studentsource中提取 全部数据,将该学生的姓名、拼音、性别、出生日期等信息赋值到表单对应的控件中去;同时将图 形控件中的src设置为该学生学号对应的图形文件名,并调用函数重新显示图片。
$("#stuid").combobox({ onSelect: function(record) { //定义选中事件 if (record){ $("#stuname").textbox("setValue",record.stuname); $("#pycode").textbox("setValue",record.pycode); $("#gender").textbox("setValue",record.gender); $("#birthdate").textbox("setValue",record.birthdate); $("#place").textbox("setValue",record.place); $("#slider1").slider('setValue',30); var src="system/images/"+record.stuid+".jpg"; $("#image1").attr('src',src); resizeImage('image1',src); } } });

⑤设置组合框的初值为第一个学生,滑块的初值为30。这时由于滑块值发生变化,其onChange 事件被触发;同时由于组合框选择了一个学生,其onSelect事件也被触发。
$("#slider1").slider('setValue',30); $('#stuid').combobox('select',studentsource[0].stuid);

⑥编写图片缩放程序。在图片的onload事件中编写程序,先计算出图片的大小尺寸,即图片的 高度和宽度;然后根据滑块值,按百分比等比例缩放图片的高度和宽度。
function resizeImage(img,src){ var image=new Image(); image.src=src; ratio=$("#slider1").val()/100.0; image.onload=function() { //必须放在onload事件中 var aheight=image.height; var awidth=image.width; if (ratio!=0){ //调整图片大小,按比例缩放 awidth = awidth * ratio; aheight = aheight * ratio; $("#image1").css({width: awidth, height: aheight}); } } }

- 42 -

《软件开发工具(jQuery) 》实例教程

实例 10. 工具栏、菜单和消息框控件的使用。
EasyUI 菜单由 EasyUI-menubutton 类指定。菜单是树型结构,即每个菜单项(menu item)之 下还可以有子菜单项。主菜单和子菜单可以通过 <div> 的嵌套来实现,也可以通过主菜单的 data-options 选项中定义 menu 属性来指定子菜单。 菜单项的图标可由 iconCls 属性指定, 菜单项之 间的分隔符由 menu-sep 类表示。简单的菜单定义举例如下:
<div id="mm" class="EasyUI-menu" style="width:120px;"> <div>New</div> <div> <span>Open</span> <div style="width:150px;"> <div><b>Word</b></div> <div>Excel</div> <div>PowerPoint</div> </div> </div> <div data-options="iconCls:'icon-save'">Save</div> <div class="menu-sep"></div> <div>Exit</div> </div>

菜单项对应的事件可以在主菜单(即 class="EasyUI-menu"的菜单)的 data-options 中指定, 也可以按下列方法定义: $('#mm').menu({ onClick:function(item){ alert(item.id); } }); 消息框(messager)提供不同样式的信息提示框,包括警示(alert) 、确认(confirm) 、提示 (prompt) 、进展(progress)等。所有的消息框都是异步的。用户可以在与消息框交互后使用回 调函数来完成一些动作。 本例在页面中定义一个工具栏、5 个 linkbutton 按钮、一个菜单按钮及其下拉菜单条、一个右 键菜单。在“新增”、“删除”和“保存”按钮事件中使用$.messager 消息框进行信息提示和操作确认。 本例程序运行界面如图 2-8 所示,其主要程序实现方法与过程如下:

图2-8

工具栏、菜单和消息框程序运行界面

- 43 -

《软件开发工具(jQuery) 》实例教程 ①首先使用layout控件将屏幕分成上下两部分,在屏幕上方定义一个工具栏;在工具栏中定义 若干个EasyUI-linkbutton按钮和一个EasyUI-menubutton菜单(“帮助”) ,每个按钮可定义一个事件。
<div id='layout' class="EasyUI-layout" style="height:500px"> <div id='toolbar' class='EasyUI-panel' data-options="region:'north'" style="overflow:hidden; background-color: #E0ECFF; height:30px; padding: 1px 1px 1px 10px;"> <a href="#" class="btn-separator"></a> <a href="#" id="btnadd" xtype="button" class="EasyUI-linkbutton" data-options="iconCls:'addIcon', plain:true, onClick:fn_add" style="">新增</a> <a href="#" id="btnedit" xtype="button" class="EasyUI-linkbutton" data-options="iconCls:'editIcon', plain:true" style="">修改</a> <a href="#" class="btn-separator"></a> <a href="#" id="btndelete" xtype="button" class="EasyUI-linkbutton" data-options="iconCls:'deleteIcon', plain:true, onClick:fn_delete" style="">删除</a> <a href="#" class="btn-separator"></a> <a href="#" id="btnsave" xtype="button" class="EasyUI-linkbutton" data-options="iconCls:'saveIcon', plain:true, onClick:fn_save" style="">保存</a> <a href="#" class="btn-separator"></a> <a href="#" id="btnrefresh" xtype="button" class="EasyUI-linkbutton" data-options="iconCls:'refreshIcon', plain:true" style="">刷新</a> <a href="#" class="btn-separator"></a> <a href="#" xtype="button" class="EasyUI-menubutton" data-options="menu:'#btnhelp_menuitem', iconCls:'helpIcon'">帮助</a> </div> <div id='bottom' data-options="region:'center'" style="padding: 2px 0px 0px 2px; "></div> </div>

②使用层嵌套方法,定义上面“帮助”菜单(btnhelp_menuitem)的两个子菜单项。
<div id="btnhelp_menuitem" style="width:150px;"> <div id="btnbookonline" data-options="iconCls:'pdfIcon'">操作说明</div> <div id="btndemo" data-options="iconCls:'wordIcon'">实例演示</div> </div>

③定义一个右键菜单myMenu1及其它的点击事件fn_myMenu1Click。该右键菜单的子菜单项通 过appendItem()方法在javascript语句中动态添加实现。
<div id="myMenu1" class="EasyUI-menu" data-options="onClick: fn_myMenu1Click" style="width: auto;"></div>
④利用appendItem()方法,逐个添加右键菜单myMenu1的六个子菜单项和两个菜单的分隔线。

$("#myMenu1").menu('appendItem', {text: '新增结点',id: 'mnadd', iconCls:'addIcon'} ); $("#myMenu1").menu('appendItem', {text: '修改记录',id: 'mnedit', iconCls:'editIcon'} ); $("#myMenu1").menu('appendItem', {text: '删除记录',id: 'mndelete', iconCls:'deleteIcon', onclick: function(){ fn_delete(); }}); $("#myMenu1").menu('appendItem', {separator:true}); $("#myMenu1").menu('appendItem', {text: '保存记录',id: 'mnsave', iconCls:'saveIcon', onclick: function(){ fn_save(); }}); $("#myMenu1").menu('appendItem',{separator:true}); $("#myMenu1").menu('appendItem',{text: '重置',id: 'mnreset', iconCls:'resetIcon'} ); $("#myMenu1").menu('appendItem',{text: '刷新',id: 'mnrefresh', iconCls:'refreshIcon'});

⑤绑定(bind)“刷新”按钮和菜单的click事件,这是另一种定义按钮和菜单事件的方法。
$("#btnrefresh,#mnrefresh").bind('click', function(e){ fn_refresh(e); });

- 44 -

《软件开发工具(jQuery) 》实例教程 ⑥定义表单的右键点击事件。 在表单myForm1中通过绑定其contextmenu事件, 采用菜单的show() 方法,实现右键菜单的弹出和触发。这里, e.preventDefault()用于禁止系统原有菜单的显示。
$('#myForm1').bind('contextmenu',function(e){ e.preventDefault(); //关闭系统原有的右键菜单 $('#myMenu1').menu('show', { left: e.pageX, top: e.pageY }); });

⑦编写各按钮和菜单的click点击事件。点击“新增”按钮,使用$.messager.show()缓缓弹出一个 消息框;点击 “ 保存 ” 按钮,使用 $.messager.alert() 弹出一个信息提示框;点击 “ 删除 ” 按钮,使用 $.messager.confirm()弹出一个信息确认框;点击 “ 重置 ” 菜单,在重置表单各个控件值之后,使用 $.messagershow()缓缓弹出一个信息提示框,2秒钟后消息框自动消失。
function fn_add(){ $.messager.show({ title:'系统提示', msg:'系统已切换至新增记录模式。<br>表单已经清空。', showType:'show', width:200, timeout:0, style:{ top: 100 } }); } function fn_save(){ $.messager.alert('系统提示','数据已经保存成功!','info'); //icon可选项: error、 question、warning } function fn_delete(){ $.messager.confirm('系统提示','是否确定删除记录?',function(r){ if (r){ alert('确定删除'); } }); } function fn_refresh(){ alert('refresh'); } function fn_myMenu1Click(item){ if (item.id=='mnreset'){ $("#main")[0].reset(); $.messager.show({ title:'系统提示', width:200, msg:'表单数据已经被重置。', timeout:2000, showType:'slide' }); } }

- 45 -

《软件开发工具(jQuery) 》实例教程

实例 11. 窗口控件 window 的应用及其函数构造。
在EasyUI中,窗口(window)是一个浮动的、可拖拽的面板,可以当作应用程序窗口使用。 默认情况下,窗口可拖动、可调整尺寸、可关闭。窗口既可以通过静态HTML定义,也可以通过JS 语句动态创建。 本例使用layout布局,将屏幕分成上、下两部分,其中屏幕上方为一个工具栏。当用户点击工 具栏中的“修改”按钮时,利用window("open")方法打开一个子窗口(myWin1) ,显示学生的详细信 息。本例程序设计的主要过程和方法如下。 ①利用HTML层<div>创建窗口myWin1控件。这里style属性中已经定义了窗口的尺寸大小。
<div id="myWin1" class="EasyUI-window" title="学生信息" data-options="iconCls:'panelIcon'" style="position:relative; width:340px; height:560px; padding:0px;"></div>

②在javascript语句中,改变窗口的一些常用属性,其中{modal: true}表示该窗口为模态窗口, 也就是说,在打开子窗口时,用户再也无法点击操作主窗口中的任何控件。
$("#myWin1").window({ closable:true, collapsible:false, resizable:false, draggable:false, modal:true, maximizable:false });

③ 在窗口中定义两个按钮,编写其中的 “ 关闭 ” 按钮的 click 事件,点击该按钮时关闭窗体 myWin1。
$("#myWin1").append("<input type='button' value='确定' id='btnok' />"); $("#myWin1").append("<input type='button' value='关闭' id='btnclose' />"); $("#btnok").css({position:'absolute', top:485, left:170, width:65}); $("#btnclose").css({position:'absolute', top:485, left:236, width:65}); $("#btnclose").on('click', function () { $("#myWin1").window('close'); });

思考题: 如何构造一个窗口定义函数?需要包括哪些参数?参考Easyui_function.js文件中的myWindow() 函数。

实例 12. 利用布局(layout)控件实现页面布局。
在 EasyUI 中,布局控件(layout)将屏幕分成五个区域(北区 north、南区 south、东区 east、 西区 west 和中区 center) ,每个区域都是一个容器,用于包含其他控件。中间区域面板(region: center)是必需的,边缘区域面板是可选的。每个边缘区域面板可通过拖拽边框调整尺寸,也可以 通过点击折叠触发器来折叠面板。布局可以嵌套,嵌套在里层的布局也分为 5 个区域,因此利用 布局可建立复杂的页面排版。当布局的选项 fit 设置为 true 时,该布局的尺寸将与它的父容器相 适应。因此,当在<body>标签上创建布局时,它将自动最大化到整个页面的全部尺寸。 本例程序运行界面如图 2-9 所示,具体布局过程与方法如下。 ①在<body>标签中创建一个布局,在该布局中创建 4 个区域面板(其中东区缺省) 。
<body id='main' class="EasyUI-layout" data-options="fit:true" style="margin: 1px 1px 1px 1px;"> <div id='top' class='EasyUI-panel' data-options="region:'north'" style="overflow:hidden; background-color: #E0ECFF; height:30px; padding: 1px 1px 1px 10px;"></div> <div id='bottom' class='EasyUI-panel' data-options="region:'south'" style="height:60px; overflow:auto;"></div> <div id='left' class='EasyUI-panel' data-options="region:'west', split:true" style="overflow:auto; width:250px;"></div> <div id='middle' class='EasyUI-panel' data-options="region:'center', split:true" style="overflow:auto;"></div> </div>
- 46 -

《软件开发工具(jQuery) 》实例教程

图 2-9

利用 layout 实现屏幕区域分割与布局

②在中间区域(id='middle')中再创建另一个布局 middlelayout,并将该区域分成左右两个部 分:middletop 和 middlebottom。
<div id='middle' class='EasyUI-panel' data-options="region:'center', split:true" style="overflow:auto;"> <div id="middlelayout" class="EasyUI-layout" data-options="fit:true"> <div id='middletop' class='EasyUI-panel' data-options="region:'north',split:true, border:false" style="overflow:auto;height:300px;"></div> <div id='middlebottom' class='EasyUI-panel' data-options="region:'center', split:true, border:false" style="overflow:auto;"></div> </div> </div>

③在左侧区域(id='left')中添加一个 EasyUI-accordion 类型的(手风琴)可折叠控件,在该 可折叠容器中添加 3 个栏目。
<div id='left' class='EasyUI-panel' data-options="region:'west', split:true" tyle="overflow:auto; width:250px;"> <div class="EasyUI-accordion" data-options="fit:true, border:false"> <div id='content1' title="C 程序设计简介"></div> <div id='content2' title="数据库原理与应用简介" data-options="selected:true"></div> <div id='content3' title="数据结构简介"></div> </div> </div>

④在 javascript 中编写程序,在 bottom 区域实时显示当前系统时间,第一个手风琴可折叠面 板中加载一个服务器端的文本文件,在第 2 和第 3 个可折叠面板中添加 HTML 文字描述。
$(document).ready(function() { setInterval(function() { //实时显示系统当前时间 var now = (new Date()).toLocaleString();
- 47 -

《软件开发工具(jQuery) 》实例教程
$('#bottom').text("系统当前时间:"+now); },1000); //提取服务器的文本文件 $('#content1').load('mybase/c-programming.txt'); //在手风琴控件中添加文字 $('#content2').append("数据库技术是计算机科学的一个重要组成部分, 基于数据库技术的计算机 应用已成为当今计算机科学与技术应用的主流,是企业开展信息化和电子商务的技术基础。数据库 原理、 技术与应用是掌握计算机应用开发技术的基础性课程, 也是一门实用性和实战性很强的课程。 "); $('#content3').html("《数据结构》的前半部分从抽象数据类型的角度讨论各种基本类型的数据结构 及其应用;后半部分主要讨论查找和排序的各种实现方法及其综合分析比较。");

⑤编写程序,在右上角区域(middletop)使用<object>标签显示一个 PDF 文件(test1.pdf) , 设置其类型为"application/pdf"。
var str='<object data="mybase/test1.pdf" type="application/pdf" width="100%" height="100%" >\n'; str+='</object>'; //swf ,,application/x-shockwave-flash, x-mplayer2 $('#middletop').append($(str));

⑥编写程序,在右下角区域(middlebottom)使用<audio>标签添加一个 mp3 文件播放器, 可以同时选择播放两个 mp3 文件。 只有当出现 controls 属性时,audio 控件及其进度控制条才会在屏 幕上显示出现。也可以添加按钮,用程序代码控制 mp3 的播放过程。
str='<p>&nbsp;新概念英语第 4 册第 1 课</p>'+ '<audio id="main_audio1" src="mybase/lesson4-01.mp3" controls="controls" autoplay="autoplay" preload="auto" loop="loop" '+ 'style="position:absolute; top:5px;left:140px; width:400px;"></audio>'+ '<p>&nbsp;新概念英语第 4 册第 2 课</p>'+ '<audio id="main_audio2" src="mybase/lesson4-02.mp3" controls="controls" '+ 'style="position:absolute; top:40px;left:140px; width:400px;"></audio>'+ '<p><button onclick="audioPlay()">播放/暂停</button>'+ '<button onclick="goToFirst()">从头播放</button></p>'; $('#middlebottom').append($(str));

相关知识: 1. <audio> 标签是 HTML 5 的新标签。autoplay 属性表示音频在就绪后马上播放,controls 属性向用户显示控件(比如播放按钮) 。Loop 属性表示音频结束时重新开始播放。Src 指定要播放 的音频的 URL。 2.可通过 append 和 html 方法添加 HTML 语句。
3.在使用<object>标签时,flash 文件(.swf)的类型设置为“application/x-shockwave-flash” 。

实例 13. 获取表单中可编辑控件的名称、类型及其值。
在jQquery中,可以通过多种方法获取页面中的所有可编辑控件的名称、类型和值。不同类型 的控件其取值方法不同。一般控件可直接使用jQuery语句$(#id).val()取值,而textbox和combobox控 件需要使用getValue方法取值。checkbox控件的取值比较复杂,可以在判断其选中状态的基础上, 使用attr()方法从属性中取值。 本例使用$('input, select, textarea').each(function(index)方法遍历一个页面所有控件,利用循环, 先使用this和attr(?type?)分别提取控件的标识符和类别,然后根据控件类别采用不同的取值方式获取 控件内容值,并将结果按照JSON格式存放到一个data变量中,在一个textarea框中显示出来。具体 方法和代码如下:
- 48 -

《软件开发工具(jQuery) 》实例教程
$('input, select, textarea').each(function(index){ var input = $(this); var id=input.attr('id'); var value=undefined; var type=input.attr('type'); var hidden=input.attr('hidden'); if (id!=undefined){ if (type=='text' && hidden!='hidden'){ value=input.textbox('getValue'); }else if (type=='combobox'){ value=input.combobox('getValue'); }else if (type=='checkbox'){ if (input.is(':checked')) value=input.attr('xtext'); }else if (type!='button'){ value=input.val(); } if (value!=undefined){ if (data!='') data+=','; data+='"'+id+'":"'+value+'"'; console.log(id+'----'+type+'----'+value); } } });

data='{'+data+'}'; $("#xformvalues").val(data); 由于获取一个控件值的程序比较繁琐, 因此可以专门构造一个自定义函数, 在给定一个控件ID 值的基础上,返回其内容值。具体方法可参考Easyui_function.js文件中的myGetInputValue()函数。 本例所属的控件遍历方法也可应用于其他事务处理中。例如,将一个表单中的所有可编辑控件 内容清空,或设置为只读状态等。 作业题: 1.根据页面中各个控件名称及其内容值,生成一条数据库Insert语句和update语句。 2. 在利用$('input, select, textarea').each(function(index)获取页面控件时, 如何避免那些不是表单 中的控件,如本例中的xformvalues,它是window窗口中的控件。

实例 14. 表单的键盘控制与控件聚焦。
在Web应用开发中,键盘操作控制可以通过绑定控件的keydown事件实现。本例创建的表单中 包含文本框、日期框、组合框、复选框等多种控件。键盘控制要求在页面初始化时将光标聚焦在第 一个控件(学号)上,当用户按下回车键、向下键(↓) 、向上键(↑)时,光标自动将聚焦到相应 的下一个或上一个控件上。本例键盘控制的具体实现过程和程序如下: ① 通 过 $('input, select, textarea').each(function(index) 遍 历 方 法 , 将 上 述 不 同 类 型 的 控 件 与 keydown事件绑定,具体控制键盘操作的程序在函数fnKeyDownEvent()中实现。 $('input, textarea').each(function(index){ var input = $(this); var id=input.attr('id'); var value=undefined; var type=input.attr('type'); var hidden=input.attr('hidden'); if (hidden!='hidden' && id!=undefined && type!='checkbox'){ if (type=='textarea'){
- 49 -

《软件开发工具(jQuery) 》实例教程 $('#'+id).on('keydown', 'input', function(e){ fnKeyDownEvent(e,id); }); }else{ $('#'+id).textbox('textbox').bind('keydown',function(e){ fnKeyDownEvent(e,id); }); } } }); ②在fnKeyDownEvent函数中,使用e.which获取当前键盘值(即用户按下的键盘值) ;通过页面 遍历,将各个控件的标识符和类别存放到数组xcmp和xtype中,并求出当前控件的数组下标,存放 到变量xno中;根据键盘值找到新聚焦控件的标识符。例如,当键盘值为回车键或向下键时,新聚 焦控件为xcmp[xno+1];当键盘值为向上键时,新聚焦控件为xcmp[xno-1]。 在 jQuery 和 EasyUI 中, textarea 控件的遍历与聚焦方式与其它控件不同, 它可直接使用 jQuery 语 句 实 现 , 例 如 : $("#"+id).focus(); 而 文 本 框 等 其 它 控 件 则 使 用 不 同 的聚 焦 方 式 , 例 如 : $("#"+id).next("span").find("input").focus();
function fnKeyDownEvent(e,id){ var key=e.which; var xcmp=[]; var xtype=[]; var i=0; if (key==13 || key==40 || key==38){ //38--up 40--down var xno=-1; $('input, textarea').each(function(index){ var input = $(this); field=input.attr('id'); type=input.attr('type'); hidden=input.attr('hidden'); if (field!=undefined && hidden!='hidden' && type!='checkbox'){ if (id==field) xno=i; xcmp[i]=field; xtype[i]=type; i++; } }); if (xno<xcmp.length && xno>=0){ var n=0; if (key==13 || key==40 ){ //向下 if (xno<=i) n=xno+1; else n=i; }else if (key==38 ){ //向上 if (xno>0) n=xno-1; else n=0; } var xnewcmp=xcmp[n]; var xtype=xtype[n]; if (xtype=='textarea') $("#"+xnewcmp).focus(); else $("#"+xnewcmp).next("span").find("input").focus(); } } }
- 50 -

《软件开发工具(jQuery) 》实例教程 ③当光标聚焦到某个控件时,实现全选该文本框中的内容,类似于有些软件开发工具中的 selectAll 的效果。
function fnSelectOnFocus(){ $('input').on('focus', function() { var $this = $(this) .one('mouseup.mouseupSelect', function() { $this.select(); return false; }) .one('mousedown', function() { $this.off('mouseup.mouseupSelect'); }) .select(); });

本例键盘控制程序仅适合于 textbox、datefield、combobox、textarea 等类型控件,对 checkbox 控件不作处理。 思考题: 如何判断 textarea 控件中光标在输入框中的第一行第一个字符的位置,这时如果按向上键, 则将光标聚焦到上一个控件上(set cursor position in a text field)。

实例 15. 利用文件框控件 file 实现文件的上传。
文件上传的方法有很多, jQuery 也有许多文件上传控件。本例采用最基本的 HTML 文件框 (<input type='file')实现文件上传,不限制上传文件的类型和大小。具体地,在表单myForm1中添 加一个学生组合框,每个学生可以上传一个照片的图形文件到服务器端,图形文件以学号命名。点 击“上传”按钮后,客户端调用服务器端程序Easyui_fileUpload.jsp文件。当文件上传成功后,通过调 用 myresizeImage()函数将图形等比例缩放后在表单规定位置中显示出来。客户端程序实现的主要 方法如下: ①使用jsp语句获取工程文件路径, 在javascript中获取此值,以便设置照片上传后在服务器端存 放的路径。
<% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+ request.getServerPort()+path+"/"; %> <script> var photopath='<%=basePath %>'+'mybase/students/'; … </script>

②定义表单、学号组合框及图片等控件。 ③在表单myForm1中添加一个文件选择框控件file1(input type="file") ,同时添加一个“上传”按 钮。 绑定file1控件的change事件, 只有当选择的文件为非空时, “上传”按钮才处理激活状态。 编写“上 传”按钮的点击事件,点击调用fnUpload()函数开始上传文件。
$("#myForm1").append('<input type="file" id="file1" style="position: absolute; top:260px; left:16px; width: 200px; padding-left: 4px;" />'); myButton('btnupload','myForm1','上传',260,440,25,65,'uploadIcon',''); $('#file1').bind('change',function(v){ var filename = $("#file1").val(); if (filename=='') $("#btnupload").linkbutton('disable'); else $("#btnupload").linkbutton('enable'); });
- 51 -

《软件开发工具(jQuery) 》实例教程
$('#btnupload').bind('click',function(e){ fnUpload(); }); //绑定“上传”按钮的点击事件

④ 编 写 fnUpload() 程 序 。 先 获 取 文 件 扩 展 名 并 作 判 断 , 然 后 使 用 FormData() 方 法 和 XMLHttpRequest对象,调用后台服务器端程序system//Easyui_fileUpLoad.jsp,将目标文件名和照片 文件存放路径两个参数传递给该程序。服务器端上传文件成功后,返回文件的有关信息(如文件大 小、文件扩展名等) ,并将文件选择控件置空、“上传”按钮为未激活状态,结束文件上传过程。由 于游览器缓存图片,新上传的图片不能马上在客户端显示出来,需要在图片地址src中添加一个时 间戳(timestemp) 。
var fileext=filename.substring(filename.lastIndexOf(".")+1,255).toLowerCase();//文件扩展名 var fileObj = $("#file1")[0].files[0]; // 获取文件对象 var form = new FormData(); // FormData 对象 form.append("file", fileObj);// 文件对象 var xhr = new XMLHttpRequest(); //XMLHttpRequest 对象
xhr.open("post", "system//Easyui_fileUpLoad.jsp?targetname="+targetname+"&targetpath=mybase/students", true);

xhr.onload = function () { if(xhr.status == 200){ var data = JSON.parse(xhr.responseText); if (data.error == 0) { //上传成功 var src=photopath+$("#stuid").combobox("getValue")+'.jpg?timestemp='+ new Date().getTime(); $("#image1").attr('src',src); resizeImage('image1',src,231,224); $.messager.show({ title:'系统提示', width:200, msg:'文件已经上传成功!', timeout:2000, showType:'slide' }); console.log('文件上传成功!'+src+',文件大小:'+data.filesize); }else{ $.messager.alert('系统提示','文件已上传失败!','error'); console.log(data.message); } $("#file1").val(' '); } }; xhr.send(form);

程序2-15. 文件上传服务器端程序Easyui_fileUpLoad.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ page import="java.io.*"%> <%@ page import="net.sf.JSON.JSONObject"%> <%@ page import="org.apache.commons.fileupload.FileItem"%> <%@ page import="org.apache.commons.fileupload.disk.DiskFileItemFactory"%> <%@ page import="org.apache.commons.fileupload.servlet.ServletFileUpload"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); - 52 -

《软件开发工具(jQuery) 》实例教程
String targetpath = request.getParameter("targetpath"); //目标路径 String targetname = request.getParameter("targetname"); //目标文件名称 System.out.println("target="+targetpath); String savePath = this.getServletContext().getRealPath(targetpath); File file = new File(savePath); //判断上传文件的保存目录是否存在 if (!file.exists() && !file.isDirectory()) { System.out.println(savePath+"目录不存在,需要创建"); file.mkdir(); //创建目录 } String message = ""; //消息提示 int error = 0; String targetfilename=""; String fileext=""; long xsize=0; try{ //使用Apache文件上传组件处理文件上传步骤: //1、创建一个DiskFileItemFactory工厂 DiskFileItemFactory factory = new DiskFileItemFactory(); //2、创建一个文件上传解析器 ServletFileUpload upload = new ServletFileUpload(factory); //解决上传文件名的中文乱码 upload.setHeaderEncoding("UTF-8"); //3、判断提交上来的数据是否是上传表单的数据 if(!ServletFileUpload.isMultipartContent(request)){ //按照传统方式获取数据 return; } //4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合, //每一个FileItem对应一个Form表单的输入项 List<FileItem> list = upload.parseRequest(request); //compiler5.0级以上支持 for(FileItem item : list){ //如果fileitem中封装的是普通输入项的数据 if(item.isFormField()){ String name = item.getFieldName(); //解决普通输入项的数据的中文乱码问题 String value = item.getString("UTF-8"); //value = new String(value.getBytes("iso8859-1"),"UTF-8"); System.out.println(name + "=" + value); }else{//如果fileitem中封装的是上传文件 //得到上传的文件名称和扩展名 String filename = item.getName(); fileext=filename.substring(filename.lastIndexOf(".")+1,filename.length()).toLowerCase(); targetfilename=filename; if (!targetname.trim().equals("")) targetfilename=targetname+"."+fileext; //目标文件名 if(filename==null || filename.trim().equals("")){ continue; } //注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,如:c:\a\b\1.txt,而 有些只是单纯的文件名,如:1.txt //处理获取到的上传文件的文件名的路径部分,只保留文件名部分 filename = filename.substring(filename.lastIndexOf("\\")+1); //获取item中的上传文件的输入流 InputStream in = item.getInputStream(); - 53 -

《软件开发工具(jQuery) 》实例教程
//创建一个文件输出流 //FileOutputStream out1 = new FileOutputStream(savePath + "\\" + filename); FileOutputStream out1 = new FileOutputStream(savePath + "\\" + targetfilename); //创建一个缓冲区 byte buffer[] = new byte[1024]; //判断输入流中的数据是否已经读完的标识 int len = 0; //循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据 while((len=in.read(buffer))>0){ //使用FileOutputStream输出流 //将缓冲区的数据写入到指定的目录(savePath + "\\" + filename)当中 out1.write(buffer, 0, len); } in.close(); //关闭输入流 out1.close(); //关闭输出流 item.delete(); //删除处理文件上传时生成的临时文件 message = "文件上传成功!"; File xfile = new File(savePath + "\\" + targetfilename); xsize=xfile.length(); } } }catch (Exception e) { message= "文件上传失败!"; error = 1; e.printStackTrace(); } //确定返回内容JSON格式 Map map = new HashMap(); map.put("error", error); map.put("message", message); map.put("targetfilename", targetfilename); map.put("fileext", fileext); if (xsize<=1024) map.put("filesize", xsize+"B"); else if (xsize<=1024*1000) map.put("filesize", xsize/1024.00+"KB"); else map.put("filesize", xsize/1024/1024.00+"MB"); JSONObject JSON = JSONObject.fromObject(map); response.setContentType("text/html; charset=utf-8"); PrintWriter pw = response.getWriter(); System.out.print(JSON.toString()); pw.write(JSON.toString()); %>

实例 16. 服务器端文件下载的实现。
从服务器端下载文件到客户端的实现方式有很多。本例从服务器端下载图片文件和wod文档至 客户端。首先在表单中添加一个图形控件image1和学生组合框,每个学生的照片对应于一个图片文 件, 其文件名为学号与jpg的组合 (如D2014540101.jpg) 。 图片文件下方添加一个学生简介的超链接, 其链接文件名为学号与doc文件的组合(如D2014540101.doc) 。下面给出三种不同的下载方式。 ①直接使用location.href赋值方式,例如:
window.document.location.href='system/images/'+$("#stuid").combobox("getValue")+".jpg";

在有些游览器中,这种方式会在当前网页中打开下载文件,从而改变当前打开的网页地址。 ②使用超链接<a href>方式将下载文件包含在链接地址中,例如:
<a href="mybase//D2014540101.doc">贾宝玉</a>
- 54 -

《软件开发工具(jQuery) 》实例教程 这种方式将服务器端文件打开后直接下载到本地游览器,而无需编写服务器端程序,但有些游 览器会打开一个新的页面窗口。 ③利用服务器端程序(Easyui_fileDownLoad.jsp)实现文件下载,可实现多个文件下载并命名 下载文件。具体方法和程序如下:
客户端程序: //指定源文件 var xsourcefilename=$("#image1").attr("src"); //指定目标文件 var xtargetfilename=$("#stuname").textbox("getValue")+".jpg"; //调用服务器端程序Easyui_fileDownLoad.jsp var url='system//Easyui_fileDownLoad.jsp?path='+xsourcefilename+'&name='+xtargetfilename; window.location.href=url; 服务器程序:Easyui_fileDownLoad.jsp代码: <%@page contentType="application/x-msdownload" %> <%@page language="java" import="java.util.*" pageEncoding="utf-8" %> <%@page import="com.StringUtil" import="java.io.*" %> <%@page import="java.io.BufferedInputStream" %> <%@page import="java.io.BufferedOutputStream" %> <%@page import="java.net.URLEncoder" %> <% //输入两个参数:一个源文件名称sourcefile,一个目标文件名targetfile String root = application.getRealPath("/"); String sourcefile = StringUtil.getToUtf8(request.getParameter("source")); String targetfile = StringUtil.getToUtf8(request.getParameter("target")); targetfile=URLEncoder.encode(targetfile,"UTF8"); //必须转换,否则中文乱码 String result=""; String s=root+sourcefile; String s1=s.substring(0,s.lastIndexOf("\\")); //所在文件夹 String s2=s.substring(s.lastIndexOf("\\")+1,s.length()); File f=new File(s1,s2); if (!f.exists()) { result="源文件没有找到,下载失败!"; } response.setHeader("Content-Type","application/x-msdownload;"); response.setHeader("Content-disposition","attachment; filename="+targetfile+""); BufferedInputStream bis = null; BufferedOutputStream bos = null; try { bis = new BufferedInputStream(new FileInputStream(root+sourcefile)); bos = new BufferedOutputStream(response.getOutputStream()); byte[] buff = new byte[10 * 1024]; int bytesRead; while ( -1 != (bytesRead = bis.read(buff, 0, buff.length))) { bos.write(buff, 0, bytesRead); } bos.flush(); } catch (IOException ioe) { System.out.println("下载错误:" + ioe); result="文件下载错误:<BR>"+ioe;
- 55 -

《软件开发工具(jQuery) 》实例教程
} finally { if (bis != null) bis.close(); if (bos != null) bos.close(); } if (bos !=null ){ bos.flush(); bos.close(); } bos = null; response.flushBuffer(); out.clear(); out = pageContext.pushBody(); %>

需要指出,对于不同游览器和操作系统,文件下载、保存以及打开方式有所差异。 相关知识点: ①使用tool属性,在表单panel中添加自定义按钮(本例添加了3个按钮) ②图片等比例缩放函数resizeImage()。 ③组合框的onSeelct事件。 ④<div>中元素的去除(remove()方法) 。 作业题: 1. 数据查询窗体的设计。 2.设计一个简单的计算器

- 56 -

《软件开发工具(jQuery) 》实例教程

第 3 章、EasyUI 数据库控件
实例 17. 构造连接数据库 Java 类,实现数据查询操作。
与服务器数据库进行连接操作是动态网页设计的基础。 J2EE连接数据库的一种常用方法是构造 一个java类,在各类数据库操作时调用这个类,统一进行数据库连接处理, 。 本例创建一个连接 SQL Server 数据库的类DBConn,建立一个带参数的数据库连接对象程序 setConnection,当用户指定数据库服务器名称(或地址) 、数据库用户、登录密码和连接的数据库 名时,该程序通过JDBC/jtds驱动程序连接SQL Server数据库。数据库端口号为1433,默认数据库服 务器名称为localhost,数据库用户为sa,数据库名为emlab,登录密码为sql2008。 在连接数据库时,需要在SQL Server中设置下列选项(具体设置方法见第一章) 。 ①在SQL Server配置管理器中,设置网络配置,将MSSQLServer协议中的TCP/IP启用,同时将 IP地址中的IPALL栏目上的TCP端口设置为1433; ②重新启动SQL Server服务。 创建DBConn的步骤如下: ①将jtds1.2.jar驱动程序包添加到当前工程的referenced libarary中去; ②在src下新建一个package,取名com; ③在com下新建一个class,取名setConnection; ④在public Connection setConnection中编写程序。 程序3-1-1. 数据库连接程序DBConn类代码
package com; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class DBConn { public DBConn() { } public Connection setConnection(String host, String password, String dbname, String username){ Connection conn = null; String result=""; if (host.equals("")) host="localhost"; if (password.equals("")) password="sql2008"; if (dbname.equals("")) dbname="examples"; if (username.equals("")) username="sa"; String url = "jdbc:jtds:sqlserver://"+host+":1433;DatabaseName="+dbname; try{ Class.forName("net.sourceforge.jtds.jdbc.Driver"); conn = DriverManager.getConnection(url, username, password); result="success"; }catch (ClassNotFoundException e){ e.printStackTrace(); result=e.getMessage(); }catch (SQLException e){ e.printStackTrace(); result=e.getMessage(); } return conn; } }

- 57 -

《软件开发工具(jQuery) 》实例教程 借助DBConn类,可以在后台JSP程序中连接数据库,实现各类数据库操作。其中数据查询操作 (select语句)的主要步骤如下: ①在JSP页面中创建一个Connection对象,调用DBConn类,指定数据库服务器、sa用户、登录 密码和数据库名等参数(database默认值为:localhost sa sql2008 emlab),连接数据库;具体 语句如下: DBConn con=new DBConn(); Connection connection=con.getConnection(database); //database为数据库连接字符串 ②创建一个Statement对象,生成具有给定类型和并发性的ResultSet对象;具体语句如下: Statement stmt=connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); ③使用executeQuery()和getResultSet()方法执行查询语句,生成一个ResultSet对象rs(结果集) ; 具体语句如下: stmt.executeQuery(sqlString); ResultSet rs=stmt.getResultSet(); ④利用循环对rs逐行进行输出处理,将查询结果保存到缓存变量中,具体语句如下: ResultSetMetaData rsmd=rs.getMetaData(); //获取列信息 rs.beforeFirst(); while(rs.next()) { //循环提取各行数据 …… } 对结果集进行处理时,rs.last()指向查询结果集的最后一行,此时的行号rs.getRow()就是查询结 果集的总行数,rs.getString()获取rs当前行中某一列的值。输出数据符合JSON格式,该格式数据举 例如下:
[ {"areaid":"110000","areaname":"北京市"}, {"areaid":"120000","areaname":"天津市"}, {"areaid":"130000","areaname":"河北省"}, {"areaid":"140000","areaname":"山西省"}, …… {"areaid":"650000","areaname":"新疆维吾尔自治区"} ]

这里,每行内容由大括号{ }包含,大括号内为某一行各个列的名称及其值,列名和列值用双 引号包含,各列之间用逗号分隔。 ⑤将缓存变量中的查询结果返回给客户端。具体语句如下: response.getWriter().write(record.toString()); 本例包含客户端和服务器端两个程序。服务器端程序调用DBConn 类连接数据库,在数据库 emlab中执行一条客户端发送的SELECT查询语句,从areas表中提取省份编码和名称。客户端程序 通过$.ajax调用服务器端程序Easyui_getComboxData.jsp, 使用success方法接受服务器端返回的结果, 并将查询结果显示在一个textarea控件中,具体语句如下:
$.ajax({ url: "system\\Easyui_getComboxData.jsp", data: { database: sysdatabasestring, sqlString: xsql }, async: false, success: function(data) { $("#result").val(data); } });

- 58 -

《软件开发工具(jQuery) 》实例教程 这里,客户端向服务器端发送两个变量:①数据库连接字符串(localhost sa sql2008 emlab),该字符串将数据库服务器名、数据库用户名、登录密码、数据库名等四个参数组合 在一起,中间用tab键分隔。传至服务器端后,后台JSP程序用split语句再把这个字符串分解为四个 参数,这样处理的目的是为了减少传送变量的数量;②SELECT查询语句,可以包含合法的CTE、 衍生表等。本实例程序运行界面如图3-1所示。

图3-1

JSP数据库查询操作以及JSON格式数据返回界面

实例 18. 服务器端数据更新语句的执行。
数据更新语句主要是指除查询语句之外的其他 SQL语句,如INSERT、UPDATE、DELETE、 CREATE等语句。由于这些语句运行之后不直接返回结果集,因此在服务器端的程序与前面所述的 查询语句不同, 通常是通过executeUpdate()方法实现。 客户端可以将多条数据更新语句组合在一起, 一次性地传递给服务器端运行,但不同语句之间不能出现GO语句。 本例利用服务器端程序实现数据库更新操作,包括新建数据表、插入记录、删除记录等。点击 “创建”按钮,在数据库emlab中新建一个省份表 myProvinces;点击“数据”按钮,使用insert…select 语句将areas表中的省份编码和名称等列批量插入到新表中;点击“删除”按钮,删除省份表中的前20 行。 每次数据更新后, 查询语句将myProvinces表中最新数据以JSON格式显示在一个textarea控件中。 本例程序运行界面如图3-2所示,服务器端实现数据库更新操作的主要步骤如下。

图3-2

JSP数据库更新操作程序运行界面 - 59 -

《软件开发工具(jQuery) 》实例教程 ①创建Connection对象,调用DBConn类,连接数据库,具体方法与数据查询相同。 ②创建一个Statement对象,具体方法与数据查询相同。 ③使用executeUpdate()方法执行数据更新语句,并利用try判断数据更新是否成功。如果失败, 则通过e.getMessage()返回错误信息。 ④向客户端返回SQL命令执行结果。 程序3-18:服务器端数据库更新程序代码。
<%@ page language="java" import="java.util.*" import="java.sql.*,com.DBConn" pageEncoding="utf-8"%> <%@page import="com.StringUtil"%> <% Statement stmt=connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet. CONCUR_READ_ONLY); if (!updatesql.equals("")){ try{ stmt.executeUpdate(updatesql); }catch (SQLException e){ errmsg=e.getMessage(); } } stmt.close(); connection.close(); System.out.println("errmsg="+errmsg); if (errmsg.equals("")){ response.getWriter().write("{'error':''}"); }else{ response.getWriter().write("{'error':\""+errmsg+"\"}"); } %>

其他知识点: ①JS中全局变量与局部变量的定义 sql=" "; //(全局变量,不带var) var sql=" "; //(局部变量,带var) ②客户端解析服务器端返回的JSON数据方法。 success: function(data) { eval("var result="+data); //服务器端返回的值赋值到result变量中 } ③linkbutton按钮状态设置。 $("#cmdinsert").linkbutton("enable"); //激活 $("#cmdinsert").linkbutton("disable"); //未激活 思考题: 1.本例在使用ajax在服务器端执行数据更新语句之后还需要执行数据查询语句,而查询语句 的执行也要使用ajax。怎样在服务器端编写一个JSP程序,既可以执行数据更新语句有可以执行查 询语句? 2.在客户端编写判断程序,当myProvinces表中没有记录时,将cmddelete按钮变成未激活(灰 色)状态。

- 60 -

《软件开发工具(jQuery) 》实例教程

实例 19. 服务器端存储过程和用户定义函数的调用。
SQL Server存储过程和用户定义函数都可以包含输入/输出参数。 标量用户定义函数可作为一个 列进行输出(通常需要为其指定一个别名) ,因此可使用查询语句返回其计算结果。在JSP中,存储 过程的调用相对比较复杂些,其核心是参数的定义、赋值及返回取值,主要方法和步骤如下: ①连接数据库emlab,与执行查询语句和更新语句相同; ②通过CallableStatement的prepareCall()方法,用问号(?)指定存储过程的输入输出参数个数; CallableStatement stmt=connection.prepareCall("{ call sys_getpycode(?, ?) }"); ③根据输入参数的类型,使用setString("@输入参数", 参数值)方法为输入参数赋值。日期型、 整型和浮点型输入参数分别使用setDate()、setFloat()、setInt()方法赋值; stmt.setString("@str",chnstr); ④使用registerOutParameter(("@参数名称", 参数类型)方法,指定输出参数的类型。字符型参数 使 用 java.sql.Types.VARCHAR , 日 期 型 、 整 型 和 浮 点 型 数 据 分 别 使 用 Types.INTEGER 和 Types.FLOAT。 stmt.registerOutParameter("@pycode",java.sql.Types.VARCHAR); ⑤使用execute()方法执行存储过程,计算出结果; stmt.execute(); ⑥使用getString("@输出参数")等方法获取来自存储过程输出参数的返回值。 String str=stmt.getString("@pycode"); ⑦使用JSON格式将服务器端各个输出参数的结果只返回至客户端。 response.getWriter().write("{pycode:'"+str+"'}"); 本例调用服务器端的一个SQL Server存储过程sys_getPycode(具体代码见sys_getpycode.sql) , 其功能是输入一个中文姓名,返回该姓名对应的汉语拼音。这里,将stuname和pycode这两个文本 框控件的buttonIcon属性分别设置为locateIcon和helpIcon,这时文本框的右侧各出现一个小按钮。点 击小按钮,将触发文本框的onClickButton事件,客户端程序将通过ajax调用服务器端的存储过程或 用户定义函数,服务器计算出汉语拼音后返回至客户端,由客户端程序将拼音值赋值到pycode控件 中。可以发现,用户定义函数的调用比存储过程要简便很多,在服务器端只需要调用通用查询程序 即可。本例程序运行界面如图4-3所示,服务器端完整程序见example19_getpycode_server.jsp,客户 端程序的设计过程和方法如下。

图4-3

客户端调用服务器端存储过程和用户定义函数

- 61 -

《软件开发工具(jQuery) 》实例教程 ①在表单中定义学生相关信息的控件。 ②在学生姓名对应的文本框(stuname)的右侧添加一个小图标按钮,在其点击事件中编写代码, 通过example19_getpycode_server.jsp程序调用服务器端的存储过程,然后将存储过程计算结果返回, 赋值给拼音对应的文本框中去。
$('#stuname').textbox({ buttonIcon:'locateIcon', onClickButton: function(e){ $.ajax({ url: "example19_getpycode_server.jsp", data: { database: sysdatabasestring, chnstr: $("#stuname").textbox("getValue") }, async: false, success: function(data) { eval("var result="+data); } }); } }); //返回存储过程输出参数的结果 $("#pycode").textbox("setValue",result.pycode);

③采用类似的方法,在汉语拼音对应的文本框(pycode)的右侧添加一个小图标按钮,在其点 击事件中编写代码,将用户定义函数dbo.sys_GenPycode()作为查询语句的一个列进行输出(别名为 pycode) ,调用服务器端程序easyui_execSelect.jsp后将用户定义函数的结果返回客户端。
$("#pycode").textbox({ buttonIcon:'helpIcon', onClickButton: function(e){ var xsql="select dbo.sys_GenPycode('"+$("#stuname").textbox("getValue")+"') as pycode"; $.ajax({ url: "system\\easyui_execSelect.jsp", data: { database: sysdatabasestring, selectsql:xsql }, async: false, success: function(data) { eval("var result="+data); $("#pycode").textbox("setValue",result[0].pycode); } }); }

思考题: 是否可以在stuname控件的onChange事件中编写程序实现同步显示学生姓名的拼音?

实例 20. 动态 combobox 组合框控件的定义与初值设置。
组合框的数据源也可以是基于远程服务器端符合规定格式的数据, 有时把这种从数据库中取数 据的组合框称为动态组合框。在EasyUI中,动态与静态组合框的定义相同,不同的只是数据来源。 可以有不同的方法实现动态组合框。本例采用ajax将数据库查询语句从客户端传送给服务器端,服 务器端将查询结果以数组形式返回客户端,然后与组合框的data属性相绑定,这样组合框中就出现 数据库中数据选项。下面以“党派(party)”组合框为例,具体阐述其中的定义步骤:
- 62 -

《软件开发工具(jQuery) 》实例教程 ①使用JS语句在myFieldset1中定义party组合框控件,在组合框之外添加一个层,用于确定控件 的显示位置。 var str='<div id="party_div"><input class="EasyUI-combobox" id="party"></div>'; $("#myFieldset1").append($(str)); ②设置层的样式,即层的绝对坐标位置(可以调用myTextCss()函数实现) 。 $("#party_div").css({position:'absolute', padding:'0px 2px 0px 4px', top:'185px', left:'86px', 'z-index':2}); ③定义党派组合框属性值,包括组合框宽度、下拉选项的行数(按像数计算) 、内容列与显示 列(valueField、textField)等。
$("#party").combobox({ width:160, panelHeight: 'auto', valueField: 'party', textField: 'party' }); //自动计算行数,选项比较少时适用

④采用ajax调用服务器端程序Easyui_getComboxData.jsp,客户端发送查询语句sql.party给服务 器端;服务器端将查询结果按JSON格式返回给客户端的data变量,data变量经过eval计算后赋值给 source数组变量;将source数组与组合框的data属性绑定,并选定第一个选项为组合框的初值。
$.ajax({ type: "Post", url: "system/Easyui_getComboxData.jsp", data: {database: sysdatabasestring, selectsql: jqsql.party}, async: false, success: function(data) { //返回的数据用data获取内容,直接复制到客户端数组source var source=eval(data); $("#party").combobox({data: source}); //绑定data属性,从此产生选项数据 //设置组合框初值为第一个选项 if (source.length > 0) { $("#"+id).combobox('select', source[0].party); } }, error: function(err) { console.log(err); } });

这里,Easyui_getComboxData.jsp是一个服务器端后台程序,该程序对于给定的一条select查询 语句,可以按JSON格式返回查询结果(包括所有行和列) ,存放在一个数组中。 从上述过程可以看出,动态组合框的定义是比较繁琐的。本例在定义其他4个组合框时,从数 据库中提取选项的这部分程序由一个函数myGetComboxData(id,sql)实现。该函数包含两个变量id和 sql,分别代表控件的标识符和查询数据的SELECT语句。 思考题: 1.能否通过调用myComboField()函数(静态组合框)和myGetComboxData()实现动态组合框 的快速定义? 2.实例中城市组合框选项有2000多条,如何与省份选项相关联进行过滤。

- 63 -

《软件开发工具(jQuery) 》实例教程

实例 21. 动态 combobox 组合框控件之间联动效果的实现。
在实际应用中,不同combobox组合框之间可能存在数据上的相互关联,即一个组合框中的选 项数据源与另一个组合框的取值有关。 例如在实例20中, 教师出生地所在的省份与城市都是组合框, 但城市选项依赖于省份选项,即当某个省份被选定时,所在城市的选项应当限制在这个省份所属的 那些城市内, 这就是说两个组合框之间存在联动效应。 本例实现省份与城市组合框之间的联动效应, 程序运行界面如图3-3所示,主要实现过程和方法如下。

图3-3. 动态组合框combobox之间联动的实现

①定义省份和城市两个动态组合框,城市组合框先不从数据库中取数,即为空选项,而省份组 合框调用myGetComboxData()函数从数据库中提取选项。
$("#provinceid").combobox({ width:160, panelHeight: 'auto', valueField: 'provinceid', textField: 'province' }); $("#cityid").combobox({ width:160, panelHeight: 'auto', valueField: 'cityid', textField: 'city' }); myGetComboxData('provinceid',jqsql.province);

//体用函数从数据库中提取省份选项的数据

②在省份组合框的onSelect事件中编写程序,当用户选定某个省份时,编写城市组合框的查询 语句,即时从数据库中提取城市组合框的选项值,具体程序如下:
- 64 -

《软件开发工具(jQuery) 》实例教程
$("#provinceid").combobox({ onSelect: function(record) { //定义选项被选中的事件 if (record) { //判断选项是否为空 var xvalue = $("#provinceid").combobox('getValue'); //提取省份选项的值 //确定城市选项取数的查询语句 var sql="select * from ("+jqsql.city+") as p where provinceid='"+xvalue+"'"; $("#city").combobox('clear'); //清空城市组合框中原来的选项 myGetComboxData('cityid',sql); //从数据库中提取新的城市选项 } } });

有关combobox的定义可用控件自定义函数myDBComboField()快速实现: myDBComboField('provinceid','myFieldset1','出生地:', 70, 33*7+20, 16, 0, 135, jqsql.province, 'province',''); 思考题: 1.实例中省份选项的初值为空,城市选项也为空。为省份选项的设置一个初值,这时城市组 合框是否有选项,选项是否正确? 2. 组合框过滤是指当用户输入一个字符串时, 组合框中只显示与其关键字 (通常为拼音助记码) 中相匹配的那些选项,而将其他选项剔除或过滤掉,以快速定位和选择。EasyUI 组合框是否具有 选项过滤的功能?

实例 22. 服务器端取数据库中数据赋值到表单。
本例创建一个教师信息表单,要求输入教师编码,点击“刷新”按钮后,客户端程序从服务器提 取该教师的全部信息,并以JSON格式返回数据,然后填充到表单的各个控件中去。如果教师编码 对应的记录不存在,则予以警告提示。本实例实现步骤和方法如下: ①将页面中除教师编码之外的所有控件设置为只读状态。 不同类型的控件其只读状态的设置方 法不同。例如:checkbox和combobox可以使用disable方法禁用。
$('input, select, textarea').each(function(index){ var input = $(this); id=input.attr('id'); type=input.attr('type'); hidden=input.attr('hidden'); if (id!=undefined && hidden!='hidden'){ if (type=='text') $("#"+id).textbox('readonly',true); else if (type=='textarea') $("#"+id).attr('readonly',true); else if (type=='combobox') $("#"+id).combobox('disable'); else if (type=='checkbox') $("#"+id).attr('disabled',true); else $("#"+id).attr('readonly',true); } });

上述控件只读状态的设置也可以直接调用自定义函数mySetFormReadonly()实现: mySetFormReadonly(true); ② 根 据 教 师 编 码 值 , 创 建 SELECT 查 询 语 句 ; 调 用 ajax 和 服 务 器 端 公 共 查 询 程 序 Easyui_execSelect.jsp获取查询结果;将查询结果赋值到result数组变量中。
var sql="select * from teachers where teacherid='"+$("#teacherid").textbox('getValue')+"'"; var result=[];
- 65 -

《软件开发工具(jQuery) 》实例教程
$.ajax({ type: "Post", url: "system/Easyui_execSelect.jsp", data: {database: sysdatabasestring, selectsql: sql}, async: false, success: function(data) { //返回的数据用data获取内容,直接复制到客户端数组source eval("result="+data+";"); } });

上述服务器端执行查询语句的功能也可以调用自定义函数实现: var data=myRunSelectSql(sysdatabasestring, sql); eval("result="+data+";"); ③由于result是数组变量,可以根据result.length的值来判断教师编码是否存在。如果教师编码 在数据库中不存在,则用$.messager.alert()方法予以警告提示。 if (result.length==0){ $.messager.alert('系统提示', '<br>&nbsp;教师编码找不到!', 'error'); } ④如果数据库中找到教师编码,则将result中所有教师信息赋值到控件中(由于result是数组变 量,而且查询结果只有一行,故使用result[0]表示这一行) 。这个过程由$.each(result[0], function(id, value) { }方法实现, jQuery可以循环式地将JSON数据中每一个列的标识符id和值value取出来, 如果 该标识符id对应的控件存在,则把value值赋值给这个控件。需要注意的是,不同类型的控件其赋值 方式也不同,这个与控件取值方法类似。
$.each(result[0], function(id, value) { //each循环取值 var input = $("#"+id); var type=input.attr('type'); if (input!=undefined){ if (type=='text'){ input.textbox('setValue',value); }else if (type=='combobox'){ input.combobox('setValue',value); }else if (type=='checkbox'){ if (input.attr('masterid')==''){ if (input.is(':checked')) input.attr('value',value); } }else{ input.val(value); } } });

相关知识点: <BackSpace>键的禁用。当页面中有控件是只读状态时,点击键盘上的<BackSpace>键,一些游 览器会退出当前页面返回到上一个地址的页面上去。本例调用函数myBanBackSpace()直接实现。 作业题: 编写一个函数mySetCmpReadOnly(fields),要求输入一个控件名称集,设置该控件集中所有控 件的只读状态,各个控件之间用分号分隔。

- 66 -

《软件开发工具(jQuery) 》实例教程

实例 23. 客户端和服务器端表单数据验证。
在 EasyUI 中,数据验证可分为客户端(本地)和服务器端(远程)两种层次。客户端又可以 按照数据的基本规则实施控件级和表单级验证。控件级验证可以在控件定义时采用 validatebox 设 置规则(例如是否为有效的 email、url 等) ,也可以利用扩展的 validatebox 正则表达式;表单级验 证则在表单提交时根据业务规则进行判断,以确保数据在保存到数据库之前是完整正确的。 除此之外,有些数据的验证必须借助服务器端才能完成,例如新增一个客户,其客户编码是 否存在重复;输入一个用户账号,判断该账号是否存在,等等。 本例创建一个表单,采用客户端和服务器端相结合对表单数据进行正确性验证。数据验证规 则及其实现方法具体描述如下: ①控件级验证。email 地址和 homepage 主页必须符合规定格式。 直接利用控件的 validType 属性进行验证,代码如下: $("#email").textbox({validType:'email'}); $("#homepage").textbox({validType:'url'}); ②控件级正则表达式验证。教师姓名必须为有效的汉字;姓名拼音只能是英文字符;出生日 期必须大于 1949-10-01 小于系统当前日期;教师编码由 7 位数字组成。 这项验证可以利用扩展的validatebox,具体方法是先定义一个规则名称(如integer、date、CHS 等),然后在$.extend($.fn.validatebox.defaults.rules, {})中编写程序,具体代码如下:
$('#teacherid').textbox({ validType:"integer" //integer为自己定的规则名称,下同。 }); $('#birthdate').datebox({ validType:"date" }); $('#name').textbox({ validType:"CHS" }); $('#pycode').textbox({ validType:"english" }); //验证程序 $.extend($.fn.validatebox.defaults.rules, { date: { //自定义的规则名称,下同 validator: function(value, param){ var now = new Date(); var d1 = new Date('1949-10-01'); var d2 = new Date(now.getFullYear(), now.getMonth(), now.getDate()); var d3 = now.getFullYear()+'-'+now.getMonth()+'-'+now.getDate(); return d1<=new Date(value) && new Date(value)<=d2; }, message: '日期必须在1949-10-01与'+today+'之间!' }, CHS:{ //验证汉字 validator:function(value){ return /^[\u0391-\uFFE5]+$/.test(value); }, message:"教师姓名只能输入汉字!" }, english : {// 验证英文字母 validator : function(value) { return /^[A-Za-z]+$/i.test(value);
- 67 -

《软件开发工具(jQuery) 》实例教程
}, message : '姓名拼音只能输入英文字符!' }, integer : {// 验证整数 validator : function(value) { return /^[+]?[1-9]+\d*$/i.test(value); }, message : '教师编码只能输入数字!' }, });

③表单级验证。教师编码不能为空,并由 8 数字组成,前 4 位为 1970~今年之间有效的年份; 教师姓名不能为空;出生日期不能为空。
var errormsg=[]; //存放数据验证发现的错误信息 //先判断各个控件是否符合格式要求 if (!$("#teacherid").textbox('isValid')) errormsg.push('教师编码输入错误!'); if (!$("#name").textbox('isValid')) errormsg.push('教师姓名输入错误!'); if (!$("#pycode").textbox('isValid')) errormsg.push('姓名拼音输入错误!'); if (!$("#birthdate").datebox('isValid')) errormsg.push('出生日期输入错误!'); if (!$("#email").textbox('isValid')) errormsg.push('Email 地址格式错误!'); if (!$("#homepage").textbox('isValid')) errormsg.push('个人主页格式错误!'); //判断其他逻辑 var s1=$("#teacherid").textbox('getValue'); var s2=$("#name").textbox('getValue'); var s3=$("#province").combobox('getText'); var s4=$("#city").combobox('getText'); if (s1.length==0) errormsg.push('教师编码不能为空!'); if (s1.length!=8) errormsg.push('教师编码必须是 8 位数字!'); else if (s1.substring(0,4)<'1970' || s1.substring(0,4)>now.getFullYear()){ errormsg.push('教师编码前 4 位年份超出范围!'); } if (s2.length==0) errormsg.push('教师姓名不能为空!');

④服务器端验证。教师编码必须是独一无二的;由于教师籍贯所对应的省份和所在城市是可 以编辑的,因此必须验证这两个值在地区表(areas)中是否合法存在的。 ? 教师编码的唯一性验证:通过查询语句在 teachers 表中检索教师编码是否存在,如果存在 重复,则查询结果返回值的数组长度大于 0。
var sql="select * from teachers where teacherid='"+s1+"'"; var result=myRunSelectSql(sysdatabasestring,sql); //result 为数组变量 if (result.length>0){ errormsg.push('教师编码重复!'); }

? 省份及城市的存在性验证:通过查询语句按省份名称检索地区表 areas,如果省份名称不 存在,则返回值的数组长度为 0。
var sql1="select areaid as provinceid from areas where areaname='"+s3+"'"; var result1=myRunSelectSql(sysdatabasestring,sql1); if (result1.length==0){ //数组长度为0,表示无返回结果 errormsg.push('省份名称输入错误!'); }

? 在存在的省份中去查找输入的城市是否存在, 如果不存在或不属于所属的省份, 则返回输 入错误信息。
var sql2="select 1 as n from areas where areaname='"+s4+"' and parentnodeid='"+result1[0].provinceid+"'";
- 68 -

《软件开发工具(jQuery) 》实例教程
var result2=myRunSelectSql(sysdatabasestring,sql2); if (result2.length==0){ errormsg.push('城市名称输入错误!'); }

⑤输出验证出错信息。前面各种验证发现的错误信息被存放到一个数组变量 errormsg 中,将 该数组中的各条验证错误信息分行显示在一个消息警告框中。
if (errormsg.length>0){ var str=''; for (var i=0;i<errormsg.length;i++){ str+='<br>'; if (i>0) str+='<span style="padding:0px 0px 0px 42px;">'+errormsg[i]+'</span>'; else str+=errormsg[i]; } $.messager.alert('系统提示','数据验证发现下列错误,提交失败!<br>'+str,'error'); }

综上所述,由于控件级验证只能提示数据错误信息,而不能有效防止错误数据保存到数据库 中去,因此完整有效的数据验证应当在表单提交前通过必要的程序设计才能实现。

实例 24. 服务器端数据库记录的增删改操作。
在Web开发技术中, 许多应用程序是由数据库记录增加、 修改、 删除和查询等操作组合而成的, 因此数据库记录的增删改操作是构成一个应用系统的最基本单元。 本例将前面所述的数据库连接、数据查询、数据库更新、数据验证等知识进行综合应用,构造 一个教师信息编辑程序。页面的左侧使用一个表单(myForm1)将教师编码和名称通过HTML超链 接显示出来, 每个超链接记录一个序号, 同时包含一个复选框checkbox控件。 点击超链接或复选框, 调用 fnSetRecord () 函数,根据序号从教师数据源数组中提取数据,然后显示在页面右侧的表单 (myForm2)控件中。

图3-4 数据库记录增删改操作实现

- 69 -

《软件开发工具(jQuery) 》实例教程 工具栏提供教师记录的新增、修改、删除、保存和刷新等按钮。新增教师时表单各控件值被重 置;修改教师信息时教师编码被设置为只读,其他控件为可编辑状态;删除教师时提醒用户确认, 使用DELETE语句直接删除记录;记录保存前从客户端和服务器端对数据进行验证;保存记录时对 新增或修改数据这两种情况进行区分,这里使用一个隐藏控件变量(addoredit)进行标记。数据保 存或删除后,调用fnRefresh()函数重新从数据库中提取教师信息显示在页面的左侧超链接中。本例 程序运行界面如图3-4所示,具体实现过程和方法如下: ①构造fnRefresh()数据刷新函数,建立教师超链接。 ? 从服务器端教师表 (teachers) 库中提取教师信息, 保存到一个数组变量teacherdata中 (JSON 格式)。
var sql="select rtrim(teacherid)+' '+rtrim(name) as teacher,* from teachers"; var result=myRunSelectSql(sysdatabasestring,sql); teacherdata=result;

?

构造教师信息的超链接,每个超链接包括一个层(用于坐标定位)和复选框checkbox,超 链接内容为教师编码与教师姓名的组合。每个超链接的click事件调用一个fnSetRecord(n) 函数, 其功能是将当前超链接对应的教师信息从数组teacherdata中赋值到右侧表单控件中, 因此在函数中需要一个参数记录教师序号n。
var str=''; for (var i=1;i<=result.length;i++){ //定义每个教师的超链接 str+='<div id="itemrowno'+i+'" style="position:absolute; left:6px; top: '+ (26*(i-1)+10)+'px;" >'; str+='<input type="checkbox" id="itemcheckbox'+i+'" onClick="return fnSetRecord('+( i)+');" >'; str+='<a href="#" onClick="return fnSetRecord('+(i)+');" >' + result[i-1].teacher + '</a></div>'; }

?

将各个超链接添加到左侧的panel控件(myForm1)中,添加之前需先清空原有超链接。
$("#myForm1").empty(); //清除原来的超链接 $("#myForm1").append($(str));

?

超链接构造完成之后,调用fnSetRecord(1)函数,将光标定位在第一个教师超链接上。这 时右侧屏幕显示第一位教师的基本信息。 fnSetRecord(1);

②在函数fnSetRecord(n)中,从数组teacherdata[]中取值,将超链接对应的第n个教师的数据赋值 到表单myForm2的控件中。 ? 直接调用自定义函数mySetFormValuesbyJSON加以实现。具体代码见Easyui_function.js文 件中。 mySetFormValuesbyJSON(teacherdata[n-1]); ? 每个超链接都有一个checkbox复选框,但同时只能打钩选中一个(即第n个)。实现的方 法是:利用循环和prop("checked", false)方法,打钩选中当前超链接上的checkbox,去掉其 他超链接上的checkbox。
for (var i=1;i<=teacherdata.length;i++){ if (i==n) $("#itemcheckbox"+i).prop("checked", true); else $("#itemcheckbox"+i).prop("checked", false); //$("#itemcheckbox"+i).prop("checked", (i==n)? true: false) }
- 70 -

《软件开发工具(jQuery) 》实例教程 ? 使用一个隐藏控件addoredit,记录当前操作为记录修改状态(即非记录新增状态) $("#addoredit").val('edit');

将当前教师信息显示在右侧的myForm2上之后,将其控件设置成只读状态(readonly=true)。 可以调用用户自定义函数mySetReadonly(' ', true)实现。具体代码如下。
function mySetReadonly(c, flag){ //对函数定义的控件(包括xid自定义属性的)只读 //c为空时,对所有xid属性非空的控件设置只读 var xfields=[]; if (c!='') xfields=c.split(';'); else{ var k=0; $('input, select, textarea').each(function(index){ var input = $(this); if (input.attr('id')!=undefined && input.attr('xid')!=undefined && input.attr('xid')!=''){ xfields[k]=input.attr('id'); console.log(xfields[k]+'----'+input.attr('xid')); k++; } }); } var type=''; var id=''; var value=''; var hidden=''; var pid=''; //checkbox的大组名称 for (k=0;k<xfields.length;k++){ //var input = $(this); var input=$("#"+xfields[k]); id=input.attr('id'); type=input.attr('type'); hidden=input.attr('hidden'); if (id!=undefined && hidden!='hidden'){ if (type=='text') $("#"+id).textbox('readonly',flag); else if (type=='textarea') $("#"+id).attr('readonly',flag); else if (type=='combobox') $("#"+id).combobox('readonly',flag); else if (type=='checkbox') $("#"+id).attr('disabled',flag); else $("#"+id).attr('readonly',flag); } } }

③在函数fnAdd()编写程序。在新增记录时完成下列各个操作: ? 将表单中原有教师信息清空(本例采用重置(reset)的方式),其中combobox和checkbox 控件的值不重置。此项功能通过调用myreSetForm()自定义函数实现,其具体代码如下:
function myreSetForm(){ //重置表单 var type=''; var id=''; var value=''; var hidden=''; $('input, select, textarea').each(function(index){ var input = $(this); id=input.attr('id');
- 71 -

《软件开发工具(jQuery) 》实例教程
type=input.attr('type'); hidden=input.attr('hidden'); if (id!=undefined){ if (type=='text' && hidden!='hidden') $("#"+id).textbox('reset'); else if (type=='textarea') $("#"+id).val(''); else if (type=='combobox'){ //值不变 } else if (type=='checkbox' || type=='checkboxgroup'){ //值不变 }else{ $("#"+id).val(''); } } }); }

?

将表单中的各个控件设置为非只读(readonly=false),即可编辑状态。这项功能通过调用 函数实现。
mySetFormReadonly(false);

?

由于右侧myForm2表单使用标签页(Tabs),新增记录时将光标锁定在第一个页面上,并 聚焦教师编码这个控件上。
$("#myTab").tabs('select',0); $("#teacherid").next("span").find("input").focus(); $("#teacherid").select(); //IE不支持 //新增记录状态值

?

最后将addoredit值设置为新增add,因为在记录保存时需要区分是新增记录还是修改记录。
$("#addoredit").val('add');

④在函数fnEdit()编写程序。在修改记录时完成下列各个操作,具体描述参考新增记录的方法。 不同的是,修改记录时,主键(教师编码)不能修改,还是只读状态。
mySetFormReadonly(false); $("#teacherid").textbox('readonly',true); //新增记录 $("#myTab").tabs('select',0); $("#teacherid").next("span").find("input").focus(); $("#teacherid").select(); //IE不支持 $("#addoredit").val('edit'); //修改记录

⑤在函数fnDelete编写程序。在删除记录时,使用$.messager.confirm()先由用户确定是否真的需 要删除记录。待确定删除后,编写 DELETE语句,调用函数myRunUpdateSql(sysdatabasestring,sql) 执行数据库中记录删除操作。删除记录后需要刷新数据,即从数据库中重新提取数据,生成屏幕左 侧的各个超链接,这项功能可直接调用前面所述的fnRefresh()函数实现。
var keyvalue=$("#teacherid").textbox("getValue"); $.messager.confirm('系统提示','删除教师编码'+keyvalue+"<br>是否确定?",function(r){ if (r){ var sql="delete teachers where teacherid='"+keyvalue+"'"; var result=myRunUpdateSql(sysdatabasestring,sql); if (result.error==''){ fnRefresh(); }else{ console.log(result.error); }
- 72 -

《软件开发工具(jQuery) 》实例教程
} }); function myRunUpdateSql(databasestring, sql){ //单行结果集 result={}; $.ajax({ type: "Post", url: "system/Easyui_execUpdate.jsp", data: {database: sysdatabasestring, updatesql: sql}, async: false, success: function(data) { //返回的数据用data获取内容,直接复制到客户端数组source eval("result="+data); }, error: function(err) { console.log(err); } }); return (result); }

⑥在函数fnSave编写程序保存记录。与前面操作相比,记录保存往往是比较繁琐的。首先需要 判断和验证数据是否正确,然后判断是新增记录之后还是修改记录之后进行保存,最后发送SQL数 据更新语句由服务器端执行。具体过程和方法如下: ? 验证进行表单级和服务器端数据验证,本例通过调用数据验证函数fnValidation()实现,并 将数据验证结果进行返回。这个函数有一个参数addoredit,用来区分是新增或修改j记录状 态。数据验证如果没有发现错误,返回值1,否则返回0。
var addoredit=$("#addoredit").val(); var flag=fnValidation(addoredit); if (flag==1){ //数据验证通过 }

?

数据验证正确后,如果是新增记录后保存那么编写一条insert语句,否则编写一条 update 语句。
if (addoredit=='edit'){ //update record var sql="update teachers set "; sql+="name='"+$("#name").textbox('getValue')+"',"; sql+="pycode='"+$("#pycode").textbox('getValue')+"',"; sql+="gender='"+$("#gender").combobox('getValue')+"',"; … sql+="notes='"+$("#notes").val()+"'"; sql+=" where teacherid='"+$("#teacherid").textbox('getValue')+"'"; var result=myRunUpdateSql(sysdatabasestring,sql); }else{ //add new record var sql="insert into teachers (teacherid,name,pycode,gender,birthdate,party,"; sql+="title,province,city,degree,graduate,address,homephone,mobile,email,"; sql+="weixin,homepage,qq,research,notes) values("; sql+="'"+$("#teacherid").textbox('getValue')+"',"; sql+="'"+$("#name").textbox('getValue')+"',"; … sql+="'"+$("#research").val()+"',"; sql+="'"+$("#notes").val()+"'"; sql+=")"; }
- 73 -

《软件开发工具(jQuery) 》实例教程 ? 调用myRunUpdateSql(sysdatabasestring,sql)函数在服务器端执行SQL语句, 之后刷新超链接 数据,并将addoredit值设置为edit修改状态。
var result=myRunUpdateSql(sysdatabasestring,sql); if (result.error==''){ fnRefresh(); $("#addoredit").val('edit'); }else{ console.log(result.error); }

作业题: 1.在fnRefresh()函数中补充程序,在保存数据后,将超链接定位到当前新增或修改的那条记录 上,而不是目前的总是在第一条记录上。 2.将实例左侧的超链接改为一个DataList控件,实现教师记录增删改操作。 相关知识点: ①判断一个控件是否存在:if($("#id").length>0) ②清空容器中的子项控件:$("#myForm1").empty(); ③超链接中onclick事件的定义及触发:onClick="return fn(parm1,parm2..); " ④teacherdata变量需要定义在jQuery之外,即$(document).ready(function()之前。

实例 25. 服务器端 SQL 脚本文件.sql 的运行。
SQL Server脚本文件是一个以文本文件格式存储的SQL命令集。通常,脚本文件在SQL Server 系统中运行时语句之间可以包含GO语句, 但在服务器端运行时遇到GO语句时需要分段运行脚本。 本例在表单中创建一个可复选的组合框, 即用户可以从下拉列表中选择一个或多个SQL脚本文 件。在点击“运行脚本”按钮后,客户端将选中的脚本文件组合为一个字符串(文件之间用tab键分 隔) , 通过调用服务器端程序Easyui_runSqlScriptFile.jsp, 将选中的SQL脚本文件逐个在服务器端数 据库系统中运行。如果发现脚本文件错误,服务器端返回出错信息,显示在客户端的一个文本框 中。本例程序运行界面如图3-5所示,客户端程序的主要过程和代码如下。

图3-5. SQL脚本文件的运行程序界面

①定义一个组合框数组,包含filename和filedesc两个列;在表单中定义一个组合框,设置该组 合框的属性,将其multiple设置为true。EasyUI组合框具有多选的功能,但本身不带复选按钮。为 此需要在组合框的formatter属性中指定一个formatItem函数, 在每个选项条目中增加一个checkbox。
var filesource=[
- 74 -

《软件开发工具(jQuery) 》实例教程
{filename:"resourcecategories.sql", filedesc:"生成资源类别表"}, {filename:"dictionary.sql", filedesc:"生成选项表"}, {filename:"sys_unicodes.sql", filedesc:"生成汉字字库"}, {filename:"areas.sql", filedesc:"生成地区表"}, ]; $("#sqlfile").combobox({ width:575, panelHeight: 'auto', panelWidth: 300, editable: false, multiple:true, separator: ';', data: filesource, valueField: 'filename', textField: 'filedesc', formatter: formatItem }); function formatItem(row){ var s ='<input id="" type="checkbox" class="combobox-checkbox">'+ '<span style="font-weight:bold">' + row.filename + '</span>'+ '<span style="color:blue">' + row.filedesc + '</span>'; return s; }

②为复选框编写loadSuccess、select和unselect事件,使组合框中复选框状态与多选内容一致。
$("#sqlfile").combobox({ onLoadSuccess:function(){ var opts = $(this).combobox('options'); var target = this; var values = $(target).combobox('getValues'); $.map(values, function(value){ var el = opts.finder.getEl(target, value); el.find('input.combobox-checkbox')._propAttr('checked', true); }) }, onSelect:function(row){ var opts = $(this).combobox('options'); var el = opts.finder.getEl(this, row[opts.valueField]); el.find('input.combobox-checkbox')._propAttr('checked', true); }, onUnselect:function(row){ var opts = $(this).combobox('options'); var el = opts.finder.getEl(this, row[opts.valueField]); el.find('input.combobox-checkbox')._propAttr('checked', false); } });

③在“运行脚本”按钮中编写点击事件代码,先将组合框中选中的脚本文件逐个提取出来,连接 为 一 个 字 符 串 变 量 files 中 ( 文 件 名 之 间 以 tab 键 分 割 ), 然 后 调 用 服 务 器 端 Easyui_runSqlScriptFile.jsp,将SQL脚本文件、文件所在路径传递给服务器。服务器运行脚本后, 如果发生错误,则在一个多行文本框textarea中显示错误信息。
- 75 -

《软件开发工具(jQuery) 》实例教程
$('#btnrun').bind('click',function(e){ var files=''; var records=$("#sqlfile").combobox("getValues"); for (var i=0;i<records.length;i++){ if (i>0) files+=' '; //文件名之间以tab键分割 files+=records[i]; } $("#results").val(''); $.ajax({ url: "system\\Easyui_runSqlScriptFile.jsp", data: { database: sysdatabasestring, filename:files,filepath:'sqlscript' }, async: false, success: function(data) { var message=data.trim()+''; if (message==''){ $.messager.show({ title:'系统提示', width:200, msg:'脚本文件运行结束!', timeout:2000, showType:'slide' }); }else{ $("#results").val('错误信息返回:\n'+message); } }, error: function(err) { console.log(err); } }); });

在服务器端JSP中运行SQL脚本文件的主要方法和步骤如下: ①服务器接受参数值;连接数据库。 ②使用split分割多个SQL脚本文件。
String tmp[]; tmp=sqlfile.split(" "); //tab

③利用循环逐个处理脚本文件。先判断脚本文件是否存在,如果存在则使用FileReader打开脚 本文件。清空批语句执行缓存。
String realfile= realpath+"\\"+filepath+"\\"+tmp[i]; File f=new File(realfile); if (f.exists()){ FileReader fileReader = new FileReader(f); BufferedReader br = new BufferedReader(fileReader); …

④清空SQL批处理语句缓存;利用循环和readLine()方法逐行读取脚本文件,使用addBatch()将 读取的SQL语句添加到缓存中;判断每一条读入的语句,如果是GO语句,则执行之前保存在缓存 中的脚本语句。这样可以节省缓存,防止缓存和内存溢出。使用try语句,可以及时发现脚本文件中 的可能的错误。一旦发现错误,则终止所有脚本文件运行。
- 76 -

《软件开发工具(jQuery) 》实例教程
stmt.clearBatch(); while((str = br.readLine() ) != null){ str=str.trim(); if (!str.toLowerCase().equals("go")){ //跳过脚本中的go语句 stmt.addBatch("\n"+str); }else{ //执行go之前的sql语句 try{ tmt.executeBatch(); }catch (Exception e){ message+=e.getMessage()+"\n"; } stmt.clearBatch(); } } try{ stmt.executeBatch(); }catch (Exception e){ message+=e.getMessage()+"\n"; } if (!message.equals("")) break; }

- 77 -

《软件开发工具(jQuery) 》实例教程

第 4 章、树与数据网格及其应用
实例 26. 静态树 Tree 控件及其基本操作。
树(Tree)是一种常见的数据结构,在数据库应用系统中占有重要地位。树在网页中以树形结 构显示分层数据。它向用户提供展开、折叠、拖拽、编辑和异步加载功能。在HTML中,树定义在 <ul>元素中。该标记可定义叶节点和子节点。节点将是ul列表内的<li>元素。树也可以在一个空的 <ul>元素中定义,使用javascript加载数据。 在EasyUI中,树可以有多个根节点(第一层节点都成为根节点),树中每个节点必须有Text 和id两个列,分别为节点显示内容和节点关键字值。本例先利用javascript语句创建一个空的树,使 用append方法在树中添加一个根节点(全部地区) ,然后在根节点之下添加若干个子节点(各个省 份) ,并给出树中节点查找和选中的方法。本实例程序运行界面如图4-1所示,具体实现过程和代码 如下。

图4-1

树Tree控件及其基本操作

①使用jQuery定义树控件myTree1,设置树的lines属性为true(默认值为false)。使用append方 法,在树中添加一个根节点(全部地区),设置其parent属性为null。
var str='<div id="myTree1" class="EasyUI-tree" style="width:380px; height:500px; padding:5px;"></div>'; $("#myForm1").append($(str)); $("#myTree1").tree({ checkbox: false, lines:true}); //添加一个根节点 $("#myTree1").tree('append',{ parent: null, data:{text:"全部地区", id:"*"} });

②使用getRoot提取第一个根节点(与getRoots方法不同) ,先在该根节点之下添加一个子节点 (北京市) ,再一次性添加8个子节点(8个省份) 。
var root = $("#myTree1").tree("getRoot");
- 78 -

《软件开发工具(jQuery) 》实例教程
if (root==null) var pnode=null; else var pnode=root.target; //在根节点之下增加一个子节点 $("#myTree1").tree('append',{ parent: pnode, data:{text:"北京市", id:"110000"} }); //在根节点之下一次性增加多个子节点 $("#myTree1").tree('append',{ parent: pnode, data:[ {text:"天津市",id:"120000"}, {text:"上海市",id:"310000"}, {text:"江苏省",id:"320000"}, {text:"浙江省",id:"330000"}, {text:"安徽省",id:"340000"}, {text:"福建省",id:"350000"}, {text:"江西省",id:"360000"}, {text:"山东省",id:"370000"}, {text:"河南省",id:"410000"} ] });

③使用两种方法在树中查找节点。第一种采用find方法,根据节点ID值在树中查找某个节点; 第二种通过getChildren方法获取父节点下的所有子节点,利用循环在这些子节点中找到该节点。找 到节点后,采用append方法在该节点之下添加若干个子节点。至此,myTree1树中共有三层节点。
//方法1:根据id值和find方法查找节点,找到节点后增加其子节点 var node1=$("#myTree1").tree('find','320000'); if (node1!=null){ $("#myTree1").tree('append',{ parent: node1.target, data:[ {text:"南京市",id:"320100"}, {text:"无锡市",id:"320200"}, {text:"徐州市",id:"320300"}, {text:"常州市",id:"320400"}, {text:"苏州市",id:"320500"}, {text:"南通市",id:"320600"}, ] }); }

//方法2:取根节点的所有子节点,在子节点中根据id值查找某个节点。
var node2=null; var children = $('#myTree1').tree('getChildren', root.target); for (var i=0;i<children.length;i++){ if (children[i].id=='330000'){ //找到子节点后终止循环 node2=children[i]; break; } }
- 79 -

《软件开发工具(jQuery) 》实例教程
if (node2!=null){ $("#myTree1").tree('append',{ //添加第3层节点 parent: node2.target, data:[ {text:"杭州市",id:"330100"}, {text:"宁波市",id:"330200"}, {text:"温州市",id:"330300"}, {text:"嘉兴市",id:"330400"}, {text:"湖州市",id:"330500"}, {text:"绍兴市",id:"330600"}, ] }); }

④默认情况下, 添加子节点之后, 父节点处于自动展开状态, 这里使用collapse方法收缩该node1 节点(即将其子节点收起) 。使用select方法选中树中或聚焦某个节点。
$("#myTree1").tree('collapse', node1.target); $("#myTree1").tree('select',node2.target); //收缩父节点,与expand相反 //选中节点

主要知识点: ①append方法添加根节点和子节点 ②利用find方法查找树节点 ③树节点的收缩、展开 ④选中某个树节点

实例 27. 基于 JSON 数据的静态树加载与操作。
与静态组合框(combobox)的概念一样,静态树是指树中节点数据来自本地客户端,可以是 符合JSON格式的数据。由于树具有层次结构,因此其JSON数据必须体现父节点与子节点之间上的 下层关系。在EasyUI中,这层关系通过children这个属性及其嵌套来定义。例如,描述省份、城市 及行政区之间树型结构的JSON数据如下:
var source=[ {text:"江苏省", id:"320000"}, {text:"浙江省",id:"330000", children:[ {text:"杭州市", id:"330100", children:[ {text:"西湖区",id:"330101"}, {text:"上城区",id:"330202"}, {text:"下城区",id:"330303"}, {text:"江干区",id:"330404"} ]}, {text:"宁波市", id:"330200"}, {text:"温州市", id:"330300"}, {text:"嘉兴市", id:"330400"}, ]}, {text:"安徽省", id:"340000"} ];

本例定义一个树形结构的JSON地区数组,将数据与树的data属性绑定后构造树中节点。 为了演 示树中节点的新增、 修改和删除等操作, 本例构造一个树的右键菜单myMenu1和一个节点编辑窗口 myWin1。本例程序运行界面如图4-2所示,具体实现过程和程序代码如下:

- 80 -

《软件开发工具(jQuery) 》实例教程

图4-2

静态树节点增删改操作

①定义JSON格式数据,存放在一个数组变量areasource中。每个记录对应一个节点,每个节点 包含text和id两个列值。
var areasource=[{text:"全部地区", id:"*", children:[ {text:"北京市", id:"110000"}, {text:"天津市", id:"120000"}, {text:"上海市", id:"310000"}, {text:"江苏省", id:"320000", children:[ {text:"南京市", id:"320100"}, {text:"无锡市", id:"320200"}, {text:"徐州市", id:"320300"}, {text:"常州市", id:"320400"}, {text:"苏州市", id:"320500"}, {text:"南通市", id:"320600"} ]}, {text:"浙江省",id:"330000", children:[ {text:"杭州市", id:"330100"}, {text:"宁波市", id:"330200"}, {text:"温州市", id:"330300"}, {text:"嘉兴市", id:"330400"}, {text:"湖州市", id:"330500"}, {text:"绍兴市", id:"330600"} ]}, {text:"安徽省", id:"340000"}, {text:"福建省", id:"350000"}, {text:"江西省", id:"360000"}, {text:"山东省", id:"370000"}, {text:"河南省", id:"410000"} ]}];

②定义一个表单myForm1、 一个窗口myWin1和两个文本编辑框, 在表单中定义树控件myTree1。
- 81 -

《软件开发工具(jQuery) 》实例教程 关键之一是将树的data属性与数组areasource绑定,这时数中相应节点已经自动产生。
myForm('myForm1','main','地区信息',0,0,450,250,''); myWindow('myWin1','编辑节点',0,0,170,355,'save;cancel','close;modal'); myTextField('areaid','myWin1','地区编码:',70,33*0+14,18,0,232,'',''); myTextField('areaname','myWin1','地区名称:',70,33*1+14,18,0,232,'',''); var str='<div id="myTree1" class="EasyUI-tree" style="width:215px; height:380px; padding:5px;"></div>'; $("#myForm1").append($(str)); $("#myTree1").tree({ checkbox: false, lines:true, data: areasource }); //绑定数组

③调用自定义函数myMenu定义树myTree1的一个右键菜单myMenu1,该菜单共有4个子菜单 项,分别为新增节点、新增子节点、修改节点和删除节点。
myMenu('myMenu1',' 新 增 结 点 /mnaddnode/addIcon; 新 增 子 结 点 /mnaddsubnode/addIcon; 修 改 结 点 /mneditnode/editIcon;-;删除结点/mndeletenode/deleteIcon',' '); $("#myTree1").tree({ onContextMenu: function (e, title) { e.preventDefault(); $("#myMenu1").menu('show', { left: e.pageX, top: e.pageY }); } });

④为更好地演示树节点的各种操作,使用append方法,在找到“杭州市”这个节点的基础上,添 加5个行政区的子节点,并将光标聚焦在“杭州市”这个节点上。
var root = $("#myTree1").tree("getRoot"); //提取根节点 if (root==null) var pnode=null; else var pnode=root.target; var node1=$("#myTree1").tree('find','330100'); //查找杭州市这个节点 if (node1!=null){ $("#myTree1").tree('append',{ parent: node1.target, data:[ {text:"西湖区",id:"330101"}, {text:"上城区",id:"330202"}, {text:"下城区",id:"330303"}, {text:"江干区",id:"330404"} ] }); $("#myTree1").tree('select',node1.target); }

⑤编写节点新增节点、新增子节点和修改节点三个操作的程序。在新增节点和子节点时需要将 两个文本框内容清空;在修改节点时需要将当前节点值赋值到两个对应的文本框中。随后根据3个 不同操作类型,设置窗口myWin1的显示标题,打开窗口开始编辑数据。
$("#mnaddnode").bind('click', function(e){ //新增兄弟节点;
- 82 -

《软件开发工具(jQuery) 》实例教程
$("#areaid").textbox('setValue',''); $("#areaname").textbox('setValue',''); $("#myWin1").window({title: '新增节点'}); $("#myWin1").window('open'); }); $("#mnaddsubnode").bind('click', function(e){ //新增子节点; $("#areaid").textbox('setValue',''); $("#areaname").textbox('setValue',''); $("#myWin1").window({title: '新增子节点'}); $("#myWin1").window('open'); }); $("#mneditnode").bind('click', function(e){ //修改节点; var node=$("#myTree1").tree('getSelected'); //获取树中当前节点 if (node!=null){ $("#areaid").textbox('setValue',node.id); $("#areaname").textbox('setValue',node.text); $("#myWin1").window({title: '修改节点'}); $("#myWin1").window('open'); } });

⑥编写程序,保存节点数据。在保存数据前,先判断节点操作的类型。修改节点后保存时,只 要将文本框的值赋值到当前节点,使用使用update方法即可更新树节点。对于新增节点(即新增兄 弟节点) ,需要求出当前节点的父节点;新增子节点时,当前节点即为新节点的父节点。在确定父 节点的基础上,使用append方法增加节点,这时树中即时显示新节点。节点编辑保存后,关闭窗口 myWin1。
$("#myWin1SaveBtn").bind('click', function(e){ //点击窗体中的保存按钮 var options=$("#myWin1").window('options'); var action=options.title; var xid=$("#areaid").textbox('getValue'); var xname=$("#areaname").textbox('getValue'); var node=$("#myTree1").tree('getSelected'); if (action=='修改节点'){ node.id=xid; node.text=xname; $("#myTree1").tree('update',node); //刷新树结点 }else if (action=='新增节点'){ var node=$("#myTree1").tree('getSelected'); //获取树中当前节点 var pnode=$("#myTree1").tree('getParent', node.target); //求节点的父节点 $("#myTree1").tree('append',{ parent:pnode.target, data:{ id:xid, text:xname } }); }else if (action=='新增子节点'){ var pnode=$("#myTree1").tree('getSelected'); //获取树中当前节点 $("#myTree1").tree('append',{ parent:pnode.target, data:{ id:xid, text:xname } }); } $("#myWin1").window('close');
- 83 -

《软件开发工具(jQuery) 》实例教程
});

⑦使用getSelected方法找到树中当前节点,采用remove方法删除该节点。
$("#mndeletenode").bind('click', function(e){ //删除节点; var node=$("#myTree1").tree('getSelected'); //获取树中当前节点 if (node!=null){ var pnode=$("#myTree1").tree('getParent'); $("#myTree1").tree('remove', node.target); //删除节点 } });

相关知识点: ①每个树节点中必须有一个id值。 ②使用options获取控件的属性值,如获取窗口的标题的方法:
var options=$("#myWin1").window('options'); var action=options.title;

作业题: 1.编写程序,在新增节点保存后,将光标聚焦到新增的节点上;在伤处节点后,将光标聚焦 到树最近的兄弟节点上,兄弟节点不能存在时,则聚焦到父节点上。 2.修改本例程序,在点击新增节点和子节点菜单时,先在树中产生一个空节点,然后保存后 将文本框的值填充到新节点上去。

实例 28. 从数据库一次性加载数据到树节点。
在EasyUI中,从数据库加载数据到树节点总体是比较简单的。由于树节点可以从JSON数据中 取值,因此,只要将数据库中记录转换成JSON格式数据,就可以实现从数据库加载数据到树节点 上。可以一次性将数据库记录全部加载到树节点中,也可以通过分层逐级加载到树节点中。 本例在客户端定义一个地区分类树,其方法与实例27基本相同,只是在属性描述之后,编写一 段程序从数据库中一次性(完整)提取JSON数据返回到客户端,通过data属性加载(填充)到树中。 服务器端程序Easyui_getAllTreeNodes.jsp利用一次循环,自顶向下(而非函数递归方式)实现树中 父节点与子节点之间的嵌套,其运行效率较高。经模拟测算,服务器端生成3000个节点填充到树中 耗时不足2秒,比采用函数递归方式快3倍多。 必须指出,按照服务器端程序,存放树节点的数据库表结构有一定的规定。例如地区分类表 (areas)结构如下,记录举例如图4-3所示。
CREATE TABLE Areas( AreaID nchar(10) primary key default '', AreaName nvarchar(30) default '', PYCode nvarchar(15) default '', Zip nchar(10) default '', PhoneCode nchar(10) default '', ParentNodeID nchar(10) default '', --父节点标识符 IsparentFlag tinyint default '', --父节点或叶子节点标记值 Ancester varchar(255), --祖先节点 level tinyint default 0 --节点层次 )

- 84 -

《软件开发工具(jQuery) 》实例教程

图4-3

关系数据库中的树形结构数据示例

这里,ParentNodeID、IsparentFlag、Ancester和level这4个列是必须的,其含义分别表示每个节 点的父节点ID值、叶子节点或父节点的标记值(1-为父节点,0-为叶子节点)、祖先节点值(即各 级父节点的组合,包括父节点的父节点)和树节点所在层次。 本例客户端程序的实现过程和方法如下: ①使用javascript语句定义基本树控件myTree1,设置其lines属性为true。
var str='<div id="myTree1" class="EasyUI-tree" style="fit:auto; border: false; padding:5px;"></div>'; $("#myForm1").append($(str)); $("#myTree1").tree({ checkbox: false, lines:true });

②使用ajax调用服务器端程序Easyui_getAllTreeNodes.jsp,一次性获取数据表areas中的所有记 录, 通过data属性加载到树myTree1中。 客户端传递给服务器端主要参数为查询语句jqsql.area和关键 字areaid。
$.ajax({ url: "system\\Easyui_getAllTreeNodes.jsp", data: { database: sysdatabasestring, selectsql: jqsql.area, keyfield:'areaid', sortfield:'' }, async: false, success: function(data) { var source=eval(data); $('#myTree1').tree({ data: source }); } });
- 85 -

《软件开发工具(jQuery) 》实例教程 ③由于在EasyUI中双击父节点时,父节点不会自动展开子节点,带来操作不便。为此在树控件 中添加一个onDblClick事件,实现双击展开父节点。
$('#myTree1').tree({ //双击展开或收缩结点 onDblClick: function(node){ if (node.state=='closed') $(this).tree('expand', node.target); else $(this).tree('collapse', node.target); } });

④初始值和状态设置。由于地区节点较多,在加载完树之后,采用 collapse方法,收缩树中第 一层节点(即根节点),仅展开第三个节点(河北省),并选中这个节点。
$("#myTree1").tree('collapseAll'); var roots=$("#myTree1").tree("getRoots"); $("#myTree1").tree('expand', roots[2].target); $("#myTree1").tree('select', roots[2].target);

本例服务器端程序的实现过程和方法如下: ①连接数据库,执行查询语句,将指针指向结果集中第一条记录。
querySQL=new StringBuffer(); StringBuffer returnResult=new StringBuffer();//创建一个stringbuffer对象用于存放返回结果 String querystring=""; ResultSet node_rs=stmt.getResultSet(); if (sortfield.equals("")){ querystring="select * from ("+selectsql+") as p order by ancester+"+keyfield; }else{ querystring="select * from ("+selectsql+") as p order by ancester+"+sortfield; } querySQL.append(querystring); stmt.executeQuery(querySQL.toString()); node_rs=stmt.getResultSet(); ResultSetMetaData rsmd=node_rs.getMetaData(); int xcolcount=rsmd.getColumnCount(); node_rs.first(); node_rs.beforeFirst();

②循环处理每条记录。记录当前节点的标志值和层次值。
int xlevel=1; int flag=0; returnResult.append("["); while(node_rs.next()){ //循环输出结果集 ? 记录当前节点的标志值和层次值。 isParentFlag=node_rs.getInt("IsParentFlag"); level=node_rs.getInt("level"); str=""; ?

将当前节点的层次值level与之前节点的层次值xlevel进行比较:若两者相同(即层次没有 发生变化) ,则继续(在原来父节点上)添加兄弟节点,节点之间用逗号分隔;如果前者 小于后者(即level小于xlevel) ,则标明之前节点已经没有兄弟节点,在JSON数据中添加 若干个“]}”以封闭父节点的children属性集合。
if (level==xlevel){ if (flag==1) str+=","; }else{
- 86 -

《软件开发工具(jQuery) 》实例教程
for (i=level;i<xlevel;i++) returnResult.append("]}\n"); xlevel=level; if (flag!=0) str+=","; } str+="{\"id\":\""+StringUtil.filterNull(node_rs.getString(keyfield)).trim(). replace("\"","").replace("'","\\'")+"\""; //替换输出值中的单引号和双引号 for (j=1;j<=xcolcount;j++) { //生成一条记录的JSON数据 field=rsmd.getColumnName(j).toLowerCase(); if (!field.equals("id")){ str=str+",\""+field+"\":\""+StringUtil.filterNull(node_rs.getString(field)).trim(). replace("\"","").replace("'","\\'")+"\""; } } returnResult.append(str); //添加到结果集 ?

判断如果当前节点是父节点,则在JSON数据中添加children子节点属性;否则作为叶子节 点,结束本条记录JSON数据标识。

flag=1; if (isParentFlag==1){ returnResult.append(",\n\"children\":["); flag=0; }else{ returnResult.append("}\n"); } xlevel=level; i++; } //while

?

循环结束后对剩余的节点进行处理。

for (i=1;i<xlevel;i++) returnResult.append("]}\n"); returnResult.append("]\n");

相关知识点: ①直接调用树控件自定义函数构造树(见Easyui_functions.js文件)。 function myDBTree(id,parent,title,top,left,height,width,sql,keyfield,sortfield,style) 其中style可以是下列选项的组合:checkbox;animate;line;edit;full;menu:。举例: myDBTree( 'myTree1', 'myForm1', '地区分类', 0, 0, 0, 0, jqsql.area, 'areaid', ' ' ,' full'); ②myTree1树种第3个节点的获取方法。 ③判断节点的展开或收缩状态,根据状态再展开或收缩父节点。 ④把main层的fit设置为true,在定义myForm1时不指定表单的高度和宽度。

实例 29. 动态树节点的分层逐级加载。
当数据库记录较多时,采用一次性加载全部数据到树节点会花费较多网络资源和影响网页加 载速度。通常当树节点数超过 500 个时,需要通过分层将后台数据逐级加载到客户端树节点中。 本例定义一个地区分类树控件,先从数据库中加载第一层节点(即省份)到树中,每次只有 当用户点击展开父节点时,才将该父节点的下一层子节点从数据库中提取出来再加载到树中。这 样可以大大减少每次从数据库中提取节点的数量,加快网络访问速度。 本例程序运行界面如图 4-4 所示,分层逐级加载树节点的主要过程和方法如下:

- 87 -

《软件开发工具(jQuery) 》实例教程

图 4-4 树节点分层逐级展开程序运行界面

①定义树控件 myTree1,将其 sql 语句作为一个自定义属性保存起来,以备后用。
var str='<div id="myTree1" class="EasyUI-tree" style="fit:auto; border: false; padding:5px;"></div>'; $("#myForm1").append($(str)); $("#myTree1").tree({ checkbox: false, lines:true, }); $("#myTree1").attr('xsql', jqsql.area); //自定义属性

②利用 ajax 调用服务器端程序 Easyui_getChildNodes.jsp,从数据库中提取第一层节点(省份) 加载到树中(即 ParentNodeID 值为空的节点) 。服务器端程序在生成第一层节点时,必须判断是 叶子节点还是父节点。如果是父节点则为它添加一个空的虚拟子节点,这样父节点上就会出现一 个可以展开的小图标。树控件通过 data 属性加载节点后,必须使用 collapseAll 将所有节点收缩起 来不展开。
var sqlx="select * from ("+jqsql.area+") as p where parentnodeid=''"; $.ajax({ url: "system\\Easyui_getChildNodes.jsp", data: { database: sysdatabasestring, selectsql: sqlx, keyfield:'areaid', sortfield:''}, async: false, success: function(data) { var source=eval(data); $("#myTree1").tree({ data: source }); } }); $("#myTree1").tree('collapseAll'); //不能展开节点
- 88 -

// 第一层

//加载 JSON 数据到树

《软件开发工具(jQuery) 》实例教程 ③在树 myTree1 的点击展开事件(onBeforeExpand)中编写程序,当用户第一次点击展开某 个父节点时,先取出该父节点的关键字值,然后根据该关键字值产生一条查询语句 ,执行 Easyui_getChildNodes.jsp 程序返回子节点到 source 变量中。注意:第二次点击展开父节点时不需 要再从数据库提取数据。
$("#myTree1").tree({ onBeforeExpand: function (node){ //点击展开事件 var pid=node.id; var sql=$("#myTree1").attr('xsql'); var child_node = $("#myTree1").tree('getChildren', node.target); if (child_node.length==1 && child_node[0].id=='_ '+pid){ //判断是否是第一次点击父节点 if (sql!='') sqlx="select * from ("+sql+") as p where parentnodeid='"+pid+"'"; else sqlx=''; $.ajax({ url: "system\\Easyui_getChildNodes.jsp", data: { database: sysdatabasestring, selectsql: sqlx, keyfield:'areaid', sortfield:'' }, async: false, success: function(data) { var source=eval(data);

④删除原来的虚拟空节点,在父节点之下使用 append 方法和 data 属性添加子节点。
$("#myTree1").tree('remove', child_node[0].target); //删除子节点 $("#myTree1").tree('append', { //增加数据作为子节点 parent: node.target, data: source }); } }); }; } });

程序 2-29. 服务器端提取子节点 Easyui_getChildNodes.jsp
<%@ page language="java" import="java.util.*" import="java.sql.*,com.DBConn" pageEncoding="utf-8"%> <%@page import="com.StringUtil"%> <% request.setCharacterEncoding("ISO-8859-1"); String database=StringUtil.getUrlCHN(request.getParameter("database")); String keyfield=StringUtil.getUrlCHN(request.getParameter("keyfield")); //获取主键字段名 String sortfield=StringUtil.getUrlCHN(request.getParameter("sortfield")); String selectsql=StringUtil.getUrlCHN(request.getParameter("selectsql")); //获取要显示的所有列名 String idfield=""; StringBuffer result=new StringBuffer();//创建一个 stringbuffer 对象 用于存放最终返回结果 //System.out.println("childsql="+selectsql); //连接数据库 if (!selectsql.equals("")){ DBConn con=new DBConn(); Connection connection=con.getConnection(database); StringBuffer querySQL=new StringBuffer();//创建一个 stringbuffer 对象用来存放查询语句 Statement stmt=connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet. CONCUR_READ_ONLY); if (!sortfield.equals("")){ querySQL.append("select * from ("+selectsql+") as p order by "+sortfield); }else{ querySQL.append(selectsql); } stmt.executeQuery(querySQL.toString()); - 89 -

《软件开发工具(jQuery) 》实例教程
ResultSet node_rs=stmt.getResultSet(); //有多个结果集时,需要使用 getResultSet()方法 //System.out.println("querySQL="+querySQL.toString()); int isparentflag= -1; node_rs.last(); //移到最后一行 int rowCount =node_rs.getRow(); //得到当前行号,也就是记录数 node_rs.beforeFirst(); //如果还要用结果集,就把指针再移到初始化的位置 ResultSetMetaData rsmd=node_rs.getMetaData(); int xcolcount=rsmd.getColumnCount(); String str=""; String field=""; int i=0; int j=0; for (j=1;j<=xcolcount;j++) { field=rsmd.getColumnName(j).toLowerCase(); if (field.equals("id")){ idfield=field; break; } } if (idfield.equals("")) { idfield=keyfield; } //从数据库取记录,转换成 JSON 格式数据 while(node_rs.next()){ str="{\"id\":\""+StringUtil.filterNull(node_rs.getString(idfield)).trim(). replace("\"","").replace("'","\\'")+"\""; //这里\之后的"为普通字符 for (j=1;j<=xcolcount;j++) { field=rsmd.getColumnName(j).toLowerCase(); if (!field.equals("id")){ str=str+",\""+field+"\":\""+StringUtil.filterNull(node_rs.getString(field)).trim(). replace("\"","").replace("'","\\'")+"\""; } } isparentflag=node_rs.getInt("IsParentFlag"); if (isparentflag==1){ //下面的 closed 很重要 //子节点的值也要各不相同 =下划线+主键值 String xid="_"+StringUtil.filterNull(node_rs.getString(keyfield)).trim(). replace("\"","").replace("'","\\'")+"\""; //添加一个虚拟空节点其值为?_?+父节点值 result.append(str+",state:\"closed\",\"children\":[{\"id\":\""+xid+",\"cid\":\"\", \"text\":\" \""); if (!keyfield.equals("id")) result.append(",\""+keyfield+"\":\"\""); result.append("}]}"); //添加一个虚拟空节点 result.append((i==rowCount-1?"":",")+""); }else{ result.append(str+"}"); result.append((i==rowCount-1?"":",")+""); } i++; } node_rs.close(); stmt.close(); connection.close(); }else{ result.append("{}"); } response.getWriter().write("["+result.toString()+"]"); %>

树节点的分层逐级展开,可以大幅减少和分散从数据库中提取节点的时间,但同时增加了树 节点定位、过滤和查找的难度。

- 90 -

《软件开发工具(jQuery) 》实例教程 主要知识点: ①直接调用树控件自定义函数构造树(见Easyui_functions.js文件)。 myDBTree( 'myTree1', 'myForm1', '地区分类', 0, 0, 0, 0, jqsql.area, 'areaid', ' ' ,' '); ②虚拟空子节点的作用及其值设定。其值不能为空,因为 treegrid 中以 id 值找节点、删节点。 ③关闭某个节点 state: 'closed'

实例 30. 动态组合树 ComboTree 控件及其应用。
组合树(Combotree)是组合框(Combo)和树(tree)控件两者的结合,用户点击该控件时 它以树状结构(而非列表结构)显示数据,其树节点可以与树控件一样从数据库提取。同样地, 可以一次性从数据库中提取全部选项节点, 也可以分层逐级展开节点。 本例在输入教师的“出生地” 时使用一个组合树控件,使用分层逐级展开方法从地区分类树中选择一个城市选项。 本例程序运行界面如图 4-5 所示,主要程序代码见程序 4-30。

图 4-5 动态组合树 ComboTree 控件程序运行界面

程序 4-30:动态组合树应用程序 example30_dbcombotree.jsp
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <!doctype html> <html lang="en"> <style type="text/css"> </style> <head> <meta charset="utf-8"> <link rel="stylesheet" type="text/css" href="jqEasyUI/themes/default/EasyUI.me.css"> <link rel="stylesheet" type="text/css" href="jqEasyUI/themes/icon.css"> <link rel="stylesheet" type="text/css" href="system/css/icon.css"> <script type="text/javascript" src="jqEasyUI/jQuery.min.js"></script>
- 91 -

《软件开发工具(jQuery) 》实例教程
<script type="text/javascript" src="jqEasyUI/jQuery.EasyUI.min.js"></script> <script type="text/javascript" src="jqEasyUI/EasyUI-lang-zh_CN.js"></script> <script type="text/javascript" src="system/Easyui_functions.js"></script> </head> <body style="margin: 2px 2px 2px 2px;"> <div id='main' style="margin:0px 0px 0px 0px;"> </div> <script> $(document).ready(function() { var jqsql={}; //sql 语句中不能有双引号 jqsql.party="select Pycode as id,description as party from dictionary where Type=' 党派'"; jqsql.title="select Pycode as id,description as title from dictionary where Type='学历'"; jqsql.area="select AreaName as text, * from Areas "; jqsql.degree="select Pycode as id,description as degree from dictionary where Type=' 学历'"; myForm('myForm1','main','教师信息编辑',0,0,435,388,'close;drag'); myFieldset('myFieldset1','myForm1','',8,6,385,360); myTextField('teacherid','myFieldset1','教师编码:',70,33*0+20,16,0,160,'D20101'); myTextField('name','myFieldset1','姓名:',70,33*1+20,16,0,160,'诸葛亮'); myTextField('pycode','myFieldset1','拼音:',70,33*2+20,16,0,160,'zhugeliang');
myComboField('gender','myFieldset1','性别:',70,33*3+20,16,0,115,'男;女;take;task;book;buring','');

myDateField('birthdate','myFieldset1','出生日期:',70,33*4+20,16,0,115,'5/12/1997'); myLabelField('areaidx','myFieldset1','出生地:',33*5+20+4,16,0,0); myDBComboField('party','myFieldset1','党派:',70,33*6+20,16,0,160,jqsql.party,'','',''); myDBComboField('title','myFieldset1','职称:',70,33*7+20,16,0,160,jqsql.title,'','',''); myDBComboField('degree','myFieldset1','学历:',70,33*8+20,16,0,160,jqsql.degree,'','',''); myTextField('school','myFieldset1','毕业学校:',70,33*9+20,16,0,260,''); //定义 combotree 控件 var str='<div id="areaid_div"><input class="EasyUI-combotree" id="areaid"></div>'; $("#myFieldset1").append($(str)); $("#areaid_div").css(myTextCss(33*5+20,86,0,260)); $("#areaid").combotree({ width:220, panelHeight: 300, valueField: 'areaid', textField: 'areaname' }); $("#areaid").attr('xsql',jqsql.area); //自定义属性 $("#areaid").attr('xkeyfield','areaid'); //自定义属性 //提取第一层节点 var xsql="select * from ("+jqsql.area+") as p where parentnodeid=''"; $.ajax({ type: "Post", url: "system\\Easyui_getChildNodes.jsp", data: { database: sysdatabasestring, selectsql: xsql, keyfield:'areaid', sortfield:'' }, async: false, success: function(data) { var source=eval(data); $('#areaid').combotree({ data: source }); } }); //点击展开事件,提取子节点 $("#areaid").combotree({ onBeforeExpand: function (node){ //点击展开事件
- 92 -

《软件开发工具(jQuery) 》实例教程
var sql=$('#areaid').attr('xsql'); var keyfield=$('#areaid').attr('xkeyfield'); var pid=eval("node."+keyfield); var xcbtree=$('#areaid').combotree('tree'); var child_node = xcbtree.tree('getChildren', node.target); if (child_node.length==1 && child_node[0].id=='_'+pid){ //生成子节点 var xsql="select * from ("+sql+") as p where parentnodeid='"+pid+"'"; $.ajax({ url: "system\\Easyui_getChildNodes.jsp", data: { database: sysdatabasestring, selectsql: xsql, keyfield:keyfield, sortfield:'' }, async: false, success: function(data) { var source=eval(data); xcbtree.tree('remove', child_node[0].target); //删除子节点 xcbtree.tree('append', { //增加数据作为子节点 parent: node.target, data: source }); } }); }; } }); //选定树初始聚焦位置 var cbtree=$('#areaid').combotree('tree'); var node=cbtree.tree('find','330000'); cbtree.tree('select',node.target); }); //endofjQuery </script> </body> </html>

组合树 combotree 可以直接引用绝大部分 combo 控件的属性,但在引用树控件属性时需要先 使用 tree 方法,例如:
var xcbtree=$('#areaid').combotree('tree'); var child_node = xcbtree.tree('getChildren', node.target);

本例组合树的定义及其事件已经封装在一个函数 function myDBComboTreeField(id, parent, label, labelwidth, top, left, height, width, sql, keyfield, sortfield, style)中,其中主要参数 sql 为数据库 查询语句、keyfield 为查询语句对应的主键列、style 值为 full 时一次性从数据库提取全部节点, 否则分层逐级展开提取子节点。该函数的具体调用方法如下: myDBComboTreeField('areaid', 'myFieldset1', '出生地: ',70,33*5+20, 16,0,220, jqsql.area, 'areaid', ' ','full');

实例 31. 静态 JSON 数据网格控件基础。
数据网格(datagrid)是 EasyUI 的核心组件之一,它以一种表格的形式显示数据。与树控件 一样,网格也可以从本地获取数据或从服务器数据库中获取数据。定义数据网格时最主要的属性 是其列集合(columns) ,包括列标题、列字段名、列宽度以及对齐方式等。 本例定义一个 JSON 格式的数组变量 griddata 和一个只读数据网格控件 myGrid1。griddata 为 网格提供数据源。 myGrid1 网格的列集共包含 8 个列, 外加一个行号列和一个选择框列 (checkbox) , 每列标题居中,网格一次性显示整个数组中的全部行(即不分页) 。
- 93 -

《软件开发工具(jQuery) 》实例教程 本例程序运行界面如图 4-6 所示,主要程序设计过程和方法如下。

图 4-6 静态数据网格程序运行界面

①在 HTML 的<div>中定义数据网格控件 myGrid1。
<div id='main' style="margin:0px 0px 0px 0px;"> <div id="myGrid1" class="EasyUI-datagrid"></div> </div>

②定义网格的 JSON 数据源 (共 20 行) , 存放在一个 griddata 数组中。 JSON 数据格式中的 total 表示总的行数,rows 指定各行的值。
var griddata={"total":"200","rows":[ {"rownumber":"1","studentid":"20090202001","name":"陈蓉","pycode":"chenrong","gender":"女", "birthdate":"1995-03-22", "province":"贵州省","city":"德江县","mobile":"","homephone":"", "email":"CR1995@163.com","weixin":"chenrong766","qq":""} ,{"rownumber":"2","studentid":"20090202002","name":"蒋晓芸","pycode":"jiangxiaoyi","gender":"女", "birthdate":"1994-06-05","province":"浙江省","city":"泰顺县","mobile":"13957724282","homephone": "0577-88862276","email":"2919323406@qq.com", "weixin":"2919323406@qq.com","qq":"2919323406"} …… ,{"rownumber":"20","studentid":"20090202020","name":"唐胜利","pycode":"tangshengli","gender":"男", "birthdate":"1995-05-01","province":"浙江省","city":"慈溪市","mobile":"13905748349", "homephone":"0574-88495772","email":"tangshengli@hotmail.com","weixin":"13905748349","qq":""} ]};

③定义网格每列的标题(title) 、列字段名(field) 、列宽度等,存放在一个变量 xcolumns 中。 各个列标题水平居中 (halign:'center') , 表体内各行内容中第 4 列 (“出生日期”) 居中 (align: 'center') , 其他默认为左对齐(align: 'left') 。此外还定义一个固定列(frozenColumns) ,内容为一个复选框 (checkbox) ,存放在一个变量 xfixedcolumns 中。
var xcolumns=[[ { title: '学号', field: 'studentid', width: 90, sortable: true, halign:'center', align: 'left' }, { title: '姓名', field:'name', width: 90, halign:'center', align: 'left' }, { title: '拼音', field:'pycode', width: 110, halign:'center', align: 'left' }, { title: '出生日期', field: 'birthdate', width: 95, halign:'center', align: 'center'}, { title: '联系电话', field: 'mobile', width: 110, halign:'center', align: 'left' }, { title: '家庭电话', field: 'homephone', width: 110, halign:'center', align: 'left' }, { title: 'Email', field: 'email', width: 140, halign:'center', align: 'left' }, { title: '微信号', field: 'weixin', width: 130, halign:'center', align: 'left' } ]]; var xfixedcolumns=[[ //定义固定列 { title: 'id', field: 'id', width: 20, checkbox: true, align: 'center'} ]];
- 94 -

《软件开发工具(jQuery) 》实例教程 ④定义网格 myGrid1 的属性:使用 data 属性绑定 JSON 数组数据 griddata;使用 columns 属 性绑定列集 xcolumns;使用 frozenColumns 绑定固定列 xfixedcolumns。
$('#myGrid1').datagrid({ title: '&nbsp;学生列表', iconCls: "panelIcon", width:780, height:355, data: griddata, nowrap: true, rownumbers: true, striped: true, collapsible: true, singleSelect: true, //false, idField: 'studentid', columns: xcolumns, frozenColumns: xfixedcolumns });

相关知识点: ①网格数据的绑定可以用 data 属性绑定,也可以用 loadData 方法,例如: $('#myGrid1').datagrid('loadData', griddata); ②网格中的行号是自动产生的,与 griddata 数组中的 rownumber 无关(该列用其他用途) 。

实例 32. 动态数据库网格控件及其分页处理。
在 EasyUI 中,基于服务器端数据库的动态数据网格在定义方式上与实例 31 的静态网格十分 相似,不同只是从服务器数据库中提取据数据与分页的技术与方法。其中分页模式的设置主要包 括:①在数据网格定义时,设置 pagination 值为 true、设置分页栏的显示位置、设置 pageSize 和 pageNumber 的值(一般起始值为 1 );②设置分页栏的显示格式,包括: showPageList 、 beforePageText、afterPageText、displayMsg 等属性;③定义分页点击按钮的触发事件,执行从数 据库中提取某一页记录的查询语句。 本例首先使用 javascript 语句中定义一个数据网格 myGrid1,分页显示学生基本信息,每页显 示 10 行。在分页栏的 onRefresh、onSelectPage 和 onChangePageSize 事件中编写程序,调用服务 器端程序 Easyui_getGridData.jsp,从数据库中分页提取记录,并以 JSON 格式返回。

图 4-7. 动态数据网格分页程序运行界面 - 95 -

《软件开发工具(jQuery) 》实例教程 本例程序运行界面如图 4-7 所示,主要程序实现过程和方法如下: ①使用 append 语句在 main 层之下定义一个数据网格控件 myGrid1, 将 main 设置为一个 layout 控件,其 fit 为 true。之后,定义网格各列的标题、宽度、对其方式及列名,并定义复选框和学号 两个列为固定列。
var str='<div id="myGrid1" class="EasyUI-datagrid"></div>'; $("#main").append($(str)); var xcolumns=[[ { title: '姓名', field:'name', width: 90, halign:'center', align: 'left' }, { title: '拼音', field:'pycode', width: 110, halign:'center', align: 'left' }, { title: '出生日期', field: 'birthdate', width: 95, halign:'center', align: 'center', formatter: function(value){ value=value+''; //类型转换 return '<div align="center">' + value.substr(0,4)+'年'+value.substr(5,2)+'月' +value.substr(8,2)+'日'+'</div>'; } }, { title: '联系电话', field: 'mobile', width: 110, halign:'center', align: 'left' }, { title: '家庭电话', field: 'homephone', width: 110, halign:'center', align: 'left' }, { title: 'Email', field: 'email', width: 140, halign:'center', align: 'left' }, { title: '微信号', field: 'weixin', width: 130, halign:'center', align: 'left' } ]]; var xfixedcolumns=[[ { title: 'id', field: 'id', width: 20, checkbox: true, sortable: true, align: 'center'}, { title: '学号', field: 'studentid', width: 90, checkbox: false, sortable: true, halign:'center', align: 'left' } ]];

②设置网格属性,设置其 pagination 值为 true,pagePosition 为'bottom',每页显示 10 行(easyui 数据网格每页显示的行数必须是 10 的倍数?) 、起始页为第 1 页。
$("#myGrid1").datagrid({ title: '&nbsp;学生列表', iconCls: "panelIcon", width:780, nowrap: true, pagePosition: 'bottom', //top,both autoRowHeight: false, rownumbers: true, pagination: true, pageSize: 10, pageNumber:1, striped: true, collapsible: true, singleSelect: true, //false, idField: 'studentid', columns: xcolumns, frozenColumns: xfixedcolumns });

③定义分页模式。设置分页栏显示信息和格式 showPageList(是否可以设置每页显示行数的 组合框, 一般不需要) 、 beforePageText (页数文本框之前显示的文字, 一般设置为'第') 、 afterPageText (页数文本框之后的文字前,一般设置为: '页 共 {pages} 页') 、displayMsg(分页栏右侧显示 当前页记录行区间,一般设置为: '当前显示{from}~{to}行,共{total}行') ,其中{pages}、{from}、 {to}、{total}为系统变量,自动根据分页记录显示其值。
var pg = $("#myGrid1").datagrid("getPager"); (pg).pagination({
- 96 -

《软件开发工具(jQuery) 》实例教程
showPageList: false, //是否显示设置每页显示行数的组合框 beforePageText: '第', //页数文本框前显示的汉字 afterPageText: '页 共 {pages} 页', displayMsg: '当前显示{from}~{to}行,共{total}行' });

④在分页栏的 onRefresh、 onSelectPage 和 onChangePageSize 中编写程序, 调用 fnLoadGridData() 函数,

2015最新jquery考试题大全.doc

2015最新jquery考试题大全_IT认证_资格考试/认证_教育专区 暂无评价|0人阅读|0次下载 | 举报文档 2015最新jquery考试题大全_IT认证_资格考试/认证_教育专区。...

jQuery_V1.2_付强_2015_01_05.pdf

jQuery_V1.2_付强_2015_01_05 - www.javakc.com 1 jQuery 入门 1.1 jQuery 能做什么 jQuery 库为 Web 脚本编程提供了通用的...

HTML+JS+Jquery学习.ppt

Jquery 简介 项目实施实例练习 Q&A www.founder...2015国考面试通关宝典 89份文档 爆笑大撞脸 超爆笑...