• ExtJS4.2


    ExtJS4.2 - 从 Hello World 到 自定义组件 - 01

    经验、概述、项目搭建、国际化、HelloWorld、布局

                    —— 为爱女伊兰而奋斗             

                    ——少走弯路,简单才是王道       

    1. 写在前面

    我接触ExtJS已有两年多时间,不过之前一直用ExtJS3,近几日因为工作需要,才开始使用ExtJS4,鉴于目前手头工作不多,故将一些感受写下,希望能对其他朋友有所帮助。

    我在2011年前都没有系统的使用过WEB前端UI框架,其实那会儿,dwrextjsjquery-ui都是交替红火着,不过我是个懒惰而又保守的人,加之自己之前也用 html+css+jsavascript+el+tag 自己写过一些东西,也就没去碰这些东西,只是出于项目需要,零散的用过一些UI组件,如日历组件、树组件等。

    2011年,作为一个项目的技术架构师,应客户的要求,前端必须采用ExtJS,于是我就硬着头皮上了。初次接触ExtJS的感觉,是完全颠覆了传统WEB前端开发方式,JSP页面上空空如也,内容都在js文件中,让人大脑发蒙。从 Hello World 一路写下去,布局、单表维护、树、选择型弹窗、复杂UI,写了两个星期,才算适应了这种开发方式,终于恍然大悟,明白应该如何使用ExtJS4进行WEB前端开发。

    2013年初,本来想接触ExtJS4,然而,另一个项目要求前端必须采用JQuery Easy UI,然后就把ExtJS4丢到一边去了。在此我不得不赞赏JQuery Easy UI这个UI框架,可谓小身材大智慧,几十MB的体积,却包含了强大的功能。我只花了两天,就搭出了框架:分页搜索、查删增改、多选型下拉列表、树型下拉列表、表格型下拉列表、自定义验证、菜单、导航、布局、复杂UI;并且JQuery Easy UI的开发模式也比较吻合传统WEB前端开发方式,我对它非常认可,因此打算放弃ExtJS了。不过在此我还是必须指出,与Ext相比,JQuery Easy UI在稳定性,界面的专业化程度方面,还是稍逊一筹,不过,它依然是非常好的一个WEB前端UI组件框架,本人大力推荐!

    几天前,由于一个项目的客户要求采用ExtJS4,于是我终于捡起这个东西,起初发现它的代码与ExtJS3比较,似乎改变很大,但是深入进去看看,其实架构还是在那里,只是很多类、组件被重构,但是代码更精简了一些。在呈现后的页面上审查元素,发现元素渲染方面也有了优化。比如一个表格的单元格,之前包了几层div,现在就是1td1div。由于有了ExtJS3的基础,因此花了3天,我就从HelloWorld开始,一步步做到封装了一个查删增改的组件。

    在此我想分享一下自己使用ExtJS做开发的一点经验:

    1. 首先有心理准备,从传统WEB页面开发方式转为使用ExtJS方式,类似于从 开发转为 Java 开发,ExtJS方式是面向对象、组件化的,JSP文件只用于引入资源,页面上呈现的任何元素,都是ExtJS的组件,必须一个个创建,然后拼装组合。

      一般而言,我们页面上的元素是这样组织的

        视图 

            面板

                组件

    此外,一个弹出窗口的元素则是这样组织的

        窗口

            面板

                组件

    2. 此外,如果希望利用ExtJS的方便和美观,却又指望它速度快,那是不现实的。友情提示:谷歌浏览器解析ExtJS是最快的,最差的是IE浏览器。

    3. 开发第一步,对ExtJS4做一个概览,也就是说,了解它是什么、适应于哪些场景、整体结构是怎样的,有了这个全局观念,开发中就心中有数。千万不要一开始就让自己纠结于细节中。

    4. 然后应该开始着手写程序,从 Hello World 开始,不要嫌简陋,一步一步来,目的是大致了解使用ExtJS4开发的方式。不至于说起来头头是道,一动手就抓瞎。不过需要注意的是,ExtJS4demo,多是在 Ext.onReady 中一路写下来,初学者看了,往往写了一个页面,到下一个页面,就不知道如何把这个页面的东西移过去。因此,我建议采用代码切割的方式,更容易从全局把握。

    5. 布局、表格、表单、分页及查删增改、树型及表格型下拉列表、菜单、导航,这些都一一写过,就会有所感觉

    6. 之后可以开始写自定义类、组件,扩展Ext的一些东西

    7. 通过ExtJS4API了解常用类、组件,了解其属性、方法、事件

    可以看到,一直到7,才开始进入ExtJS4的细节了解,我再次强调,一定要从全局开始,逐步深入局部细节,并且,作为开发人员,绝大部分细节不是你需要了解的,开发中需要的、常用的,才需要认真研究一番。

    2. 开发前

    2.1. 下载

    1.下载ext-4.2.1-gpl 

    http://cdn.sencha.com/ext/gpl/ext-4.2.1-gpl.zip

    2.下载extjs4帮助文档

    3.下载 org.json.jar

    2.2. 配置tomcatserver.xml文件

    主要是配置:URIEncoding , 防止get访问时中文参数出错

    <Connector URIEncoding="UTF-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>

    2.3. 项目框架搭建

    1.Eclipse - 新建动态WEB项目(test

    2.将 org.json.jar 加入 WEB-INF/lib 

    3.将 ext-4.2.1-gpl 引入项目

    4.书写过滤器处理字符集、国际区域;书写监听器处理共享属性

    5.书写servlet处理查删增改

    6.书写all_zh_CN.js文件处理国际化公共资源

    7.书写imp.jsp文件处理前端共享资源

    1.1. 项目结构

                

    2.4. 过滤器代码

    package test.common;

    import java.io.IOException;

    import javax.servlet.Filter;

    import javax.servlet.FilterChain;

    import javax.servlet.FilterConfig;

    import javax.servlet.ServletException;

    import javax.servlet.ServletRequest;

    import javax.servlet.ServletResponse;

    import javax.servlet.http.HttpServletRequest;

    import javax.servlet.http.HttpServletResponse;

    public class EncodingFilter implements Filter {

        private String        encoding;// 编码,默认:utf-8

        public EncodingFilter() {

        }

        public void destroy() {

        }

        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

            // 编码    

         request.setCharacterEncoding(encoding);

            response.setCharacterEncoding(encoding);

            try {

                ((HttpServletResponse) response).setContentType("text/html;charset=" + encoding);

            } catch (Exception ignore) {

                

            }

            

            // 国际区域

            String strLocale = null;

            // 取会话中的语言版本

            strLocale = (String)((HttpServletRequest)request).getSession().getAttribute("strLocale");

            // 如果会话中没有指定,则取浏览器的语言版本

            if (strLocale == null) {

                strLocale = request.getLocale().toString();

            }

            request.setAttribute("strLocale", strLocale);

            chain.doFilter(request, response);

        }

        public void init(FilterConfig fConfig) throws ServletException {

            encoding = fConfig.getInitParameter("encoding");

            encoding = encoding==null?"UTF-8":encoding.trim();

            encoding = "".equals(encoding)?"UTF-8":encoding;

        }

    }

    2.5. 监听器代码

    package test.common;

    import javax.servlet.ServletContext;

    import javax.servlet.ServletContextEvent;

    import javax.servlet.ServletContextListener;

    public class ApplicationListener implements ServletContextListener {

    public ApplicationListener() {

            

        }

    public void contextInitialized(ServletContextEvent arg0) {

         ServletContext application = arg0.getServletContext();

            

         application.setAttribute("webRoot", application.getContextPath());// WEB应用根目录

         application.setAttribute("pageSize", 20);// 分页尺寸

        }

    public void contextDestroyed(ServletContextEvent arg0) {

            

        }

    }

    2.6. 查删增改Servlet代码

    package test.action;

    import java.io.IOException;

    import java.io.PrintWriter;

    import java.util.Map;

    import java.util.Map.Entry;

    import java.util.Set;

    import javax.servlet.ServletException;

    import javax.servlet.http.HttpServlet;

    import javax.servlet.http.HttpServletRequest;

    import javax.servlet.http.HttpServletResponse;

    import org.json.JSONArray;

    import org.json.JSONException;

    import org.json.JSONObject;

    public class TestAction extends HttpServlet {

    private static final long serialVersionUID = 1L;

    private static JSONArray datas;

           

        public TestAction() {

            super();

    iniDatas(); // 初始化数据

        }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    myProcess(request, response);

    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    myProcess(request, response);

    }

    // 处理入口

    private void myProcess(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    // 处理类型

    String myProcessType = request.getParameter("myProcessType");

    myProcessType = myProcessType==null?"0":myProcessType.trim();

    myProcessType = "".equals(myProcessType)?"0":myProcessType;

    if("0".equals(myProcessType)) {

    myProcess_pageQuery(request, response); // 分页搜索

    else if("1".equals(myProcessType)) {

    myProcess_save(request, response); // 添加或更新

    else if("2".equals(myProcessType)) {

    myProcess_delete(request, response); // 删除

    else if("9".equals(myProcessType)) {

    myProcess_submit(request, response); // 其他 - 测试表单提交

    }

    }

    /** 分页搜索

     * 

     * 输出 JSON对象,结构

     * {

     * total: 111,// 总行数

     * root: // 数据

     * [

     * {

     * id: "记录ID;自增型",

     * name: "姓名",

     * sex: "性别;F|M",

     * tel: "电话",

     * addr: "地址",

     * email: "Email"

     * },

     * ...

     * ]

     * }

     */

    private void myProcess_pageQuery(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    // 重写 Ext Store 的 beforload 事件传递的自定义参数

    String name = request.getParameter("name");

    String tel = request.getParameter("tel");

    // Ext Store Proxy 自动传递的分页参数

    int start = 1;

    int limit = 0;

    try {

    start = Integer.parseInt(request.getParameter("start"));

    limit = Integer.parseInt(request.getParameter("limit"));

    catch (Exception ignore) {

    }

    JSONObject joAll = getDatas(name, tel, start, limit);

    PrintWriter out = response.getWriter();

    out.println(joAll);

    }

    /** 添加或更新

     * 

     * 输出 JSON对象,结构

     * {

     * success: true|false,// 是否成功

     * msg: "消息"

     * }

     */

    private void myProcess_save(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    String id = request.getParameter("id");

    String sex = request.getParameter("sex");

    String name = request.getParameter("name");

    String tel = request.getParameter("tel");

    String addr = request.getParameter("addr");

    String email = request.getParameter("email");

    id = id==null?"":id.trim();

    PrintWriter out = response.getWriter();

    JSONObject jo = new JSONObject();

    String result = null;

    if("".equals(id)) {

    result = add(name, sex, tel, addr, email);

    else {

    result = upd(id, name, sex, tel, addr, email);

    }

    try {

    if("OK".equals(result)) {

    jo.put("success"true);

    else {

    jo.put("success"false);

    jo.put("msg", result);

    }

    catch (JSONException ignore) {

    }

    out.println(jo.toString());

    }

    /** 删除

     * 

     * 输出 JSON对象,结构

     * {

     * success: true|false,// 是否成功

     * msg: "消息"

     * }

     */

    private void myProcess_delete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    String ids = request.getParameter("ids");

    PrintWriter out = response.getWriter();

    JSONObject jo = new JSONObject();

    String result = del(ids);

    try {

    if("OK".equals(result)) {

    jo.put("success"true);

    else {

    jo.put("success"false);

    jo.put("msg", result);

    }

    catch (JSONException ignore) {

    }

    out.println(jo.toString());

    }

    /** 其他 - 测试表单提交

     * 

     * 输出 JSON对象,结构

     * {

     * success: true|false,// 是否成功

     * msg: "消息"

     * }

     */

    private void myProcess_submit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    Map<String,Object> map = request.getParameterMap();

    StringBuffer sb = new StringBuffer();

    Set<Entry<String,Object>> ets = map.entrySet();

    Object[] vals = null;

    for(Entry<String,Object> et:ets) {

    sb.append(et.getKey()).append(": ").append(joinAry((Object[])et.getValue())).append("<br/>");

    }

    PrintWriter out = response.getWriter();

    JSONObject jo = new JSONObject();

    try {

    jo.put("success"true);

    jo.put("msg", sb.toString());

    catch (JSONException ignore) {

    }

    out.println(jo.toString());

    }

    // 添加;返回 OK 表示成功,否则为失败消息

    private String add(String name, String sex, String tel, String addr, String email) {

    name = name==null?"":name.trim();

    tel = tel==null?"":tel.trim();

    sex = sex==null?"":sex.trim();

    sex = "F".equals(sex)?"F":"M";

    addr = addr==null?"":addr.trim();

    email = email==null?"":email.trim();

    if("".equals(name) || name.length()>20 || 

    "".equals(tel) || !tel.matches("^\d{10,12}$")  || 

    !"".equals(email) && !email.matches("\w+@\w+[.][a-z]+") || 

    addr.length()>50 ) {

    return "非法操作";

    }

    int len = datas.length();

    JSONObject jo = new JSONObject();

    try {

    jo.put("id", len+1);

    jo.put("name", name);

    jo.put("sex", sex);

    jo.put("tel", tel);

    jo.put("addr", addr);

    jo.put("email", email);

    catch (JSONException ignore) {

    }

    datas.put(jo);

    return "OK";

    }

    // 更新;返回 OK 表示成功,否则为失败消息

    private String upd(String id, String name, String sex, String tel, String addr, String email) {

    name = name==null?"":name.trim();

    tel = tel==null?"":tel.trim();

    sex = sex==null?"":sex.trim();

    sex = "F".equals(sex)?"F":"M";

    addr = addr==null?"":addr.trim();

    email = email==null?"":email.trim();

    if("".equals(name) || name.length()>20 || 

    "".equals(tel) || !tel.matches("^\d{10,12}$")  || 

    !"".equals(email) && !email.matches("\w+@\w+[.][a-z]+") || 

    addr.length()>50 ) {

    return "非法操作";

    }

    JSONObject jo = null;

    int len = datas.length();

    String id2 = null;

    boolean flag = false;

    for (int i = 0; i < len; i++) {

    try {

    jo = datas.getJSONObject(i);

    id2 = jo.isNull("id")?"":jo.getString("id");

    id2 = id2==null?"":id2.trim();

    if(id2.equals("") || id2.equals("D") || !id2.equals(id)) {

    continue;

    }

    jo.put("name", name);

    jo.put("sex", sex);

    jo.put("tel", tel);

    jo.put("addr", addr);

    jo.put("email", email);

    flag = true;

    break;

    catch (JSONException ignore) {

    continue;

    }

    }

    return flag?"OK":"没有该数据{"+id+"}";

    }

    // 删除;返回 OK 表示成功,否则为失败消息

    private String del(String ids) {

    if("".equals(ids)) {

    return "非法操作";

    }

    ids = ","+ids+",";

    JSONObject jo = null;

    int len = datas.length();

    String id2 = null;

    boolean flag = false;

    for (int i = 0; i < len; i++) {

    try {

    jo = datas.getJSONObject(i);

    id2 = jo.isNull("id")?"":jo.getString("id");

    id2 = id2==null?"":id2.trim();

    if(id2.equals("") || id2.equals("D") || ids.indexOf(","+id2+",")<0) {

    continue;

    }

    jo.put("id""D");// 标志删除

    flag = true;

    catch (JSONException ignore) {

    continue;

    }

    }

    return flag?"OK":"没有这些数据{"+ids+"}";

    }

    /* 分页搜索

     * 

     * @param name姓名

     * @param tel电话

     * @param start起始索引号

     * @param limit结束索引号

     * 

     * @return JSON对象,结构

     * {

     * total: 111,// 总行数

     * root: // 数据

     * [

     * {

     * id: "记录ID;自增型",

     * name: "姓名",

     * sex: "性别;F|M",

     * tel: "电话",

     * addr: "地址",

     * email: "Email"

     * },

     * ...

     * ]

     * }

     */

    private JSONObject getDatas(String name, String tel, int start, int limit) {

    name = name==null?"":name.trim();

    int len = datas.length();

    JSONObject jo = null;

    String name2 = null;

    String tel2 = null;

    JSONArray ja = new JSONArray();

    String id2 = null;

    for(int i=0;i<len;i++) {

    try {

    jo = datas.getJSONObject(i);

    id2 = jo.isNull("id")?"":jo.getString("id");

    if(id2.equals("") || id2.equals("D")) {

    continue;

    }

    if(!"".equals(name)) {

    name2 = jo.isNull("name")?"":jo.getString("name");

    name2 = name2==null?"":name2.trim();

    if(name2.indexOf(name)<0) {

    continue;

    }

    }

    if(!"".equals(tel)) {

    tel2 = jo.isNull("tel")?"":jo.getString("tel");

    tel2 = tel2==null?"":tel2.trim();

    if(tel2.indexOf(tel)<0) {

    continue;

    }

    }

    ja.put(jo);

    catch (JSONException ignore) {

    }

    }

    limit = limit<=0?20:limit;

    int total = ja.length();

    start = start>=total?total-1:(start<0?0:start);

    int end = start+limit-1;

    end = end>=total?total:(end<start?start:end);

    JSONArray ja2 = new JSONArray();

    for(int i=0;i<total;i++) {

    if(i>=start && i<=end) {

    try {

    ja2.put(ja.getJSONObject(i));

    catch (JSONException ignore) {

    }

    }

    }

    JSONObject joAll = new JSONObject();

    try {

    joAll.put("total", total);

    joAll.put("root", ja2);

    catch (JSONException ignore) {

    }

    return joAll;

    }

    /*  初始化数据,数据结构

     *  [

     *  {

     *  id: "记录ID;自增型",

     *  name: "姓名",

     *  sex: "性别;F|M",

     *  tel: "电话",

     *  addr: "地址",

     *  email: "Email"

     *  },

     *  ...

     *  ]

     */

    private void iniDatas() {

    if(datas==null) {

    datas = new JSONArray();

    JSONObject jo = null;

    for(int i=0;i<3000;i++) {

    jo = new JSONObject();

    try {

    jo.put("id", i+1);

    jo.put("name""无名氏"+(i+1));

    jo.put("sex", i%4==0?"F":"M");

    jo.put("tel""152"+(int)((99999999-11111111+1)*Math.random()+11111111));

    jo.put("addr""无名小镇"+(int)((9999-1111+1)*Math.random()+1111)+"号");

    jo.put("email""wuming"+(int)((999999-111111+1)*Math.random()+111111)+"@wuming.com");

    catch (JSONException ignore) {

    }

    datas.put(jo);

    }

    }

    }

    // 辅助方法:数组的 join

    private String joinAry(Object[] ary) {

    int len = ary==null?0:ary.length;

    if(len==0) {

    return "";

    }

    StringBuffer sb = new StringBuffer();

    for(Object o:ary) {

    sb.append(o).append(", ");

    }

    int ix = sb.lastIndexOf(",");

    if(ix>=0) {

    sb.deleteCharAt(ix);

    }

    return sb.toString();

    }

    }

    2.7. web.xml代码

    <?xml version="1.0" encoding="UTF-8"?>

    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">

      

      <display-name>test</display-name>

      

      <welcome-file-list>

        <welcome-file>index.jsp</welcome-file>

      </welcome-file-list>

      

      <!-- 应用程序启动监听器 -->

      <listener>

        <listener-class>test.common.ApplicationListener</listener-class>

      </listener>

      

      <!-- 查删增改Servlet -->

      <servlet>

        <description></description>

        <display-name>TestAction</display-name>

        <servlet-name>TestAction</servlet-name>

        <servlet-class>test.action.TestAction</servlet-class>

      </servlet>

      <servlet-mapping>

        <servlet-name>TestAction</servlet-name>

        <url-pattern>/test.do</url-pattern>

      </servlet-mapping>

      

      <!-- 编码过滤器 -->

      <filter>

        <display-name>编码过滤器,有1个参数可配置,具体见该类说明</display-name>

        <filter-name>EncodingFilter</filter-name>

        <filter-class>test.common.EncodingFilter</filter-class>

        <init-param>

          <description>编码</description>

          <param-name>encoding</param-name>

          <param-value>utf-8</param-value>

        </init-param>

      </filter>

      <filter-mapping>

        <filter-name>EncodingFilter</filter-name>

        <url-pattern>*.do</url-pattern>

      </filter-mapping>

      <filter-mapping>

        <filter-name>EncodingFilter</filter-name>

        <url-pattern>*.jsp</url-pattern>

      </filter-mapping>

      <filter-mapping>

        <filter-name>EncodingFilter</filter-name>

        <url-pattern>*.html</url-pattern>

      </filter-mapping>

      <filter-mapping>

        <filter-name>EncodingFilter</filter-name>

        <url-pattern>*.htm</url-pattern>

      </filter-mapping>

      <filter-mapping>

        <filter-name>EncodingFilter</filter-name>

        <url-pattern>*.xml</url-pattern>

      </filter-mapping>

      <filter-mapping>

        <filter-name>EncodingFilter</filter-name>

        <url-pattern>*.js</url-pattern>

      </filter-mapping>

      <filter-mapping>

        <filter-name>EncodingFilter</filter-name>

        <url-pattern>*.css</url-pattern>

      </filter-mapping>

      

    </web-app>

    2.8. all_zh_CN.js代码

    var i18n_all = {

    title: {

    dataList: "数据表格",

    addOpe: "添加操作",

    editOpe: "编辑操作",

    delOpe: "删除操作",

    guide: "第 {0} 步,共 {1} 步"

    },

    lable: {

    },

    btn: {

    pre: "上一步",

    next: "下一步",

    add: "添加",

    edit: "编辑",

    del: "删除",

    save: "保存",

    reset: "重置"

    },

    msg: {

    addConfirm: "是否确认添加",

    addOK: "添加成功",

    addErr: "添加失败",

    editConfirm: "是否确认更新",

    editOK: "编辑成功",

    editErr: "编辑失败",

    delConfirm: "是否确认删除",

    delOK: "删除成功",

    delErr: "删除失败"

    }

    };

    2.9. imp.jsp代码

    <%@ page language="java" 

    contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>

    <%-- EXT-CSS文件 --%>

    <link rel="stylesheet" type="text/css" 

    href="${webRoot }/res/extjs-4.2.0/resources/css/ext-all.css" />

    <%-- EXT-JS引导文件(根据模式决定调入 ext_all.js 或 ext_all_dev.js) --%>

    <script type="text/javascript" 

    src="${webRoot }/res/extjs-4.2.0/bootstrap.js"></script>

    <%-- EXT-国际化文件,strLocale 在过滤器中已设置 --%>

    <script type="text/javascript" 

    src="${webRoot }/res/extjs-4.2.0/locale/ext-lang-${strLocale }.js"></script>

    <script>

    // 定义3个变量,用于 .js 文件

    var global_webRoot = "${webRoot}";// WEB应用根目录 - 在监听器中已设置

    var global_pageSize = "${pageSize}";// 分页大小 - 在监听器中已设置

    var global_strLocale = "${strLocale}";// 国际区域 - 在过滤器中已设置

    </script>

    <script type="text/javascript" 

    src="${webRoot }/locale/common/all_${strLocale }.j"></script>

    3. Hello World

    3.1. 开发

    3.1.1. 创建 /locale/test_zh_CN.js文件

    var i18n_test = {

    title: {

    test1: "伊兰.ExtJS4专区"

    },

    lable: {

    },

    btn: {

    },

    msg: {

    test1: "你好!欢迎光临伊兰.ExtJS4专区!"

    }

    };

    3.1.2. 创建 /test01/test.js文件

    var i18n_my = i18n_test; // 国际化对象,见 /locale/test/test_zh_CN.js 文件

    //Ext.application({// 程序入口;作用类似 Ext.onReady ;用于 MVC 架构

    //name : "HelloExt",

    //launch : function() {

    //var p = getPanel();

    //

    //Ext.create("Ext.container.Viewport", {

    //layout : "fit",

    //items : [

    //p

    //]

    //});

    //}

    //});

    // 入口

    Ext.onReady(function(){ // 程序入口,页面加载完后会自动调用 Ext.onReady

    // 获取面板

    var p = getPanel();

    // 通过视图呈现面板

    // Viewport 为顶层容器,以页面 body 元素作为载体,呈现内容

    Ext.create("Ext.container.Viewport", {

    layout : "fit", // fit 布局:填满容器

    items : [ // Viewport包含的内容

    p

    ]

    });

    });

    // 创建并返回面板

    function getPanel() {

    //var p =   new Ext.panel.Panel({// 普通加载

    //// ...

    //});

    var p =  Ext.create("Ext.panel.Panel", {// 动态加载

    title : i18n_my.title.test1,

    html : i18n_my.msg.test1

    // 如果这个 Panel 不是通过 Viewport 呈现,则可通过 renderTo 指定呈现载体 

    //,renderTo: Ext.getBody()// 以页面 body 元素作为呈现载体

    //,renderTo: "d01"// 以ID为 d01 的元素作为呈现载体

    });

    // 返回面板

    return p;

    }

    3.1.3. 创建 /test01/test.jsp文件

    <%@ page language="java" 

    contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>

    <%@ include file="/common/imp.jsp"%><%-- 共享文件 --%>

    <%-- 本页面国际化JS文件 --%>

    <script src="${webRoot }/locale/test/test_${strLocale }.js"></script>

    <%-- 本页面功能JS文件 --%>

    <script src="${webRoot }/test01/test.js"></script>

    <%-- <div id="d01"></div> --%>

    3.1.4. 浏览

    启动服务器,浏览:http://localhost:8080/test/test01/test.jsp


    3.2. 讲解

    3.2.1. Ext.application 和 Ext.ready

    2个方法将在Ext加载完毕后自动调用

    其中,Ext.applicationExtJS4引入的新方式,用于ExtJS4MVC架构

    3.2.2. Ext.container.Viewport

    顶层容器,视图组件,可以包含其他容器类组件

    以 body 元素作为呈现载体

    主要配置为:

    layouot: “布局”,

    items: [ 成员,通常为面板 ]

    3.2.3. Ext.panel.Panel

    面板,容器类组件,可以包含其他组件,包括容器类组件

    如果不放在视图内,必需用 renderTo 指定呈现载体

    主要配置为:

    title: “标题”,

     500, // 宽度 

    height: 300, // 高度

    items: [], // 成员

    tbar: [], // 工具栏

    bbar: [], // 状态栏

    buttons: [], // 按钮

    listeners: { // 事件监听器

    activate: function(panel, eopt) {

    // 面板激活时的处理代码,panel表示面板自身

    },

    show: function(panel, eopt) {

    // 面板呈现时的处理代码,panel表示面板自身

    },

    ..

    }

    3.2.4. new ***({}) 与 Ext.create(“***”, {});

    创建Ext对象

    区别犹如java中的 new *** 与 Class.forName(“***”).newInstance()

    也就是说,后者是动态创建,这是ExtJS4的亮点,实现了按需加载

    4. 布局

    Viewport也好,Panel也好,在默认情况下,它们只能有1个成员,如果有多个成员,只会呈现第一个;那么,如何使它们能拥有和呈现多个成员呢?那么,这就要靠布局来实现。布局,就是用来组织多个成员的。

    默认的布局方式,一般是 fit ,表示成员填充整个容器

    4.1. 边界(border

    4.1.1. 概述

    如果容器需要划分为几个部分,如上中下,或左右等,凡涉及到上下左右中的,都使用边界布局,这也是最常用的布局

    边界布局的名称是 border ,它将容器划分为 上下左右中 五大块,其中,只有 中 部是必需的

    容器内的成员通过 region 属性,指示将自身装载到容器的哪个部分

    上、下:分别为 north 、 south;这两个部分必须且只能规定高度

    左、右:分别为 west、 east;这两个部分必须且只能规定宽度

    中:为 center;高度和宽度都为自动,自动填充容器剩余的部分

    4.1.2. 开发

    4.1.2.1. 修改 /locale/test_zh_CN.js文件

    var i18n_test = {

    ...,

    msg: {

    ...,

    test2_0_1: "这里是 north",

    test2_0_2: "这里是 west",

    test2_0_3: "这里是 center (伊兰.ExtJS4专区.边界布局)",

    test2_0_4: "这里是 east",

    test2_0_5: "这里是 south"

    }

    };

    4.1.2.2. 创建 /test02/test.js文件

    var i18n_my = i18n_test; // 国际化对象,见 /locale/test/test_zh_CN.js 文件

    // 入口

    Ext.onReady(function(){

    var p1 = getTop();

    var p2 = getLeft();

    var p3 = getCenter();

    var p4 = getRight();

    var p5 = getBottom();

    Ext.create("Ext.container.Viewport", {

    layout : "border", // 边界布局

    items : [

        p1,

        p2,

        p3, // 只有中部是必需的;中部的大小是自动的,不可指定的

        p4,

        p5

    ]

    });

    });

    // 头部

    function getTop() {

    var p =  Ext.create("Ext.panel.Panel", {

    html : i18n_my.msg.test2_0_1,

    height: 80, // 底部必须且只能指定高度

    border: false,

    region: "north" // 指示将自身装载到容器的头部

    });

    return p;

    }

    // 左边

    function getLeft() {

    var p =  Ext.create("Ext.panel.Panel", {

    html : i18n_my.msg.test2_0_2,

     200, // 左边必须且只能指定宽度

    collapsible: true, // 面板标题栏将出现一个 >> 图标,点击将折叠或展开面板

    split: true, // 该面板的宽度将可用鼠标调整

    region: "west" // 指示将自身装载到容器的左部

    });

    return p;

    }

    // 中部

    function getCenter() {

    var p =  Ext.create("Ext.panel.Panel", {

    html : i18n_my.msg.test2_0_3,

    bodyStyle: "border-1px 0px 1px 0px",

    region: "center" // 指示将自身装载到容器的中部

    });

    return p;

    }

    // 右边

    function getRight() {

    var p =  Ext.create("Ext.panel.Panel", {

    html : i18n_my.msg.test2_0_4,

     120, // 右边必须且只能指定宽度

    collapsible: true, // 面板标题栏将出现一个 >> 图标,点击将折叠或展开面板

    region: "east" // 指示将自身装载到容器的右部

    });

    return p;

    }

    // 底部

    function getBottom() {

    var p =  Ext.create("Ext.panel.Panel", {

    html : i18n_my.msg.test2_0_5,

    height: 40, // 底部必须且只能指定高度

    border: false,

    region: "south" // 指示将自身装载到容器的底部

    });

    return p;

    }

    4.1.2.3. 创建 /test02/test.jsp文件

    <%@ page language="java" 

    contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>

    <%-- 共享文件 --%>

    <%@ include file="/common/imp.jsp"%>

    <%-- 本页面国际化JS文件 --%>

    <script src="${webRoot }/locale/test/test_${strLocale }.js"></script>

    <%-- 本页面功能JS文件 --%>

    <script src="${webRoot }/test02/test.js"></script>

    4.1.2.4. 浏览

    浏览:http://localhost:8080/test/test02/test.jsp

    注意左右面板的 << 和 >> 按钮;注意左面板与中部的分割线


    4.2. 手风琴(accordion

    4.2.1. 概述

    我们常见页面右边是导航栏,手风琴布局可以实现

    手风琴布局的名称是 accordion

    每个成员面板都支持展开和折叠。

    在任何时间里,只有一个成员面板处于展开状态,其他都被折叠。

    注意:只有Ext.Panels和所有Ext.panel.Panel子项才可以使用accordion布局

    4.2.2. 开发

    4.2.2.1. 修改 /locale/test_zh_CN.js文件

    var i18n_test = {

    ...,

    msg: {

    ...,

    // 届时将使用 Ext.String.format 方法填充 {0} 参数

    test2_1_0: "这里是 {0} 的导航栏",

    test2_1_1: "系统管理模块",

    test2_1_2: "权限管理模块",

    test2_1_3: "基础数据管理模块",

    test2_1_4: "任务调度管理模块",

    test2_1_5: "数据同步管理模块"

    }

    };

    4.2.2.2. 创建 /test02/test1.js文件

    var i18n_my = i18n_test; // 国际化对象,见 /locale/test/test_zh_CN.js 文件

    // 入口

    Ext.onReady(function(){

    var p1 = getLeft();

    var p2 = getCenter();

    Ext.create("Ext.container.Viewport", {

    layout : "border",

    items: [

    p1,

    p2

    ]

    });

    });

    // 左边 - 整体

    function getLeft() {

    // 获取5个成员面板

    var p1 = getLeft01();

    var p2 = getLeft02();

    var p3 = getLeft03();

    var p4 = getLeft04();

    var p5 = getLeft05();

    // 创建并返回手风琴布局面板

    var p =  Ext.create("Ext.panel.Panel", {

    layout: "accordion", // 手风琴布局

    title: i18n_my.title.test2_1,

     200,

    collapsible: true,

    split: true,

    region: "west",

    items: [

    p1,

    p2,

    p3,

    p4,

    p5

    ]

    });

    return p;

    }

    // 左边 - 第 1 个成员

    function getLeft01() {

    var tt = i18n_my.msg.test2_1_1;

    var p =  Ext.create("Ext.panel.Panel", {

    title: tt,

    html : Ext.String.format(i18n_my.msg.test2_1_0, tt),

    border: false

    });

    return p;

    }

    // 左边 - 第 2 个成员

    function getLeft02() {

    var tt = i18n_my.msg.test2_1_2;

    var p =  Ext.create("Ext.panel.Panel", {

    title: tt,

    html : Ext.String.format(i18n_my.msg.test2_1_0, tt),

    border: false

    });

    return p;

    }

    // 左边 - 第 3 个成员

    function getLeft03() {

    var tt = i18n_my.msg.test2_1_3;

    var p =  Ext.create("Ext.panel.Panel", {

    title: tt,

    html : Ext.String.format(i18n_my.msg.test2_1_0, tt),

    border: false

    });

    return p;

    }

    // 左边 - 第 4 个成员

    function getLeft04() {

    var tt = i18n_my.msg.test2_1_4;

    var p =  Ext.create("Ext.panel.Panel", {

    title: tt,

    html : Ext.String.format(i18n_my.msg.test2_1_0, tt),

    border: false

    });

    return p;

    }

    // 左边 - 第 5 个成员

    function getLeft05() {

    var tt = i18n_my.msg.test2_1_5;

    var p =  Ext.create("Ext.panel.Panel", {

    title: tt,

    html : Ext.String.format(i18n_my.msg.test2_1_0, tt),

    border: false

    });

    return p;

    }

    // 中部

    function getCenter() {

    var p =  Ext.create("Ext.panel.Panel", {

    html : i18n_my.msg.test2_0_3,

    bodyStyle: "border-1px 0px 1px 0px",

    region: "center"

    });

    return p;

    }

    4.2.2.3. 创建 /test02/test1.jsp文件

    <%@ page language="java" 

    contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>

    <%-- 共享文件 --%>

    <%@ include file="/common/imp.jsp"%>

    <%-- 本页面国际化JS文件 --%>

    <script src="${webRoot }/locale/test/test_${strLocale }.js"></script>

    <%-- 本页面功能JS文件 --%>

    <script src="${webRoot }/test02/test1.js"></script>

    4.2.2.4. 浏览

    浏览:http://localhost:8080/test/test02/test1.jsp

    点击左边每个子面板,可见其他子面板被这地,被点击的面板则展开


    4.3. 卡片(card

    4.3.1. 概述

    我们常见向导界面,卡片布局可以实现

    卡片布局的名称是 card

    在任何时间里,只有一个成员面板处于激活状态,其他都被隐藏。

    需要自行开发导航按钮,以导航到不同的成员面板,实现 上一步、下一步 的功能

    注意:由于card布局需要配合导航按钮,而Viewport不具备buttons配置,故不宜直接将Viewport配置为card布局,而应用一个Panel作为card布局的总容器,再将这个Panel加入到Viewport

    4.3.2. 开发

    4.3.2.1. 修改 /locale/test_zh_CN.js文件

    var i18n_test = {

    ...,

    msg: {

    ...,

    test2_2_02: "现在进行第 {0} 步操作..."

    }

    };

    4.3.2.2. 创建 /test02/test2.js文件

    var i18n_my = i18n_test; // 国际化对象,见 /locale/test/test_zh_CN.js 文件

    var g_ix = 0; // 索引,决定card布局中,哪个成员面板被显示

    // 入口

    Ext.onReady(function(){

    var p1 = getLeft();

    var p2 = getCenter();

    Ext.create("Ext.container.Viewport", {

    layout : "border",

    items: [

    p1,

    p2

    ]

    });

    });

    // 左边 - 整体

    function getLeft() {

    // 获取5个成员面板

    var p1 = getLeft01();

    var p2 = getLeft02();

    var p3 = getLeft03();

    var p4 = getLeft04();

    var p5 = getLeft05();

    // 创建并返回手风琴布局面板

    var p =  Ext.create("Ext.panel.Panel", {

    layout: "accordion", // 手风琴布局

    title: i18n_my.title.test2_1,

     200,

    collapsible: true,

    split: true,

    region: "west",

    items: [

    p1,

    p2,

    p3,

    p4,

    p5

    ]

    });

    return p;

    }

    // 左边 - 第 1 个成员

    function getLeft01() {

    var tt = i18n_my.msg.test2_1_1;

    var p =  Ext.create("Ext.panel.Panel", {

    title: tt,

    html : Ext.String.format(i18n_my.msg.test2_1_0, tt),

    border: false

    });

    return p;

    }

    // 左边 - 第 2 个成员

    function getLeft02() {

    var tt = i18n_my.msg.test2_1_2;

    var p =  Ext.create("Ext.panel.Panel", {

    title: tt,

    html : Ext.String.format(i18n_my.msg.test2_1_0, tt),

    border: false

    });

    return p;

    }

    // 左边 - 第 3 个成员

    function getLeft03() {

    var tt = i18n_my.msg.test2_1_3;

    var p =  Ext.create("Ext.panel.Panel", {

    title: tt,

    html : Ext.String.format(i18n_my.msg.test2_1_0, tt),

    border: false

    });

    return p;

    }

    // 左边 - 第 4 个成员

    function getLeft04() {

    var tt = i18n_my.msg.test2_1_4;

    var p =  Ext.create("Ext.panel.Panel", {

    title: tt,

    html : Ext.String.format(i18n_my.msg.test2_1_0, tt),

    border: false

    });

    return p;

    }

    // 左边 - 第 5 个成员

    function getLeft05() {

    var tt = i18n_my.msg.test2_1_5;

    var p =  Ext.create("Ext.panel.Panel", {

    title: tt,

    html : Ext.String.format(i18n_my.msg.test2_1_0, tt),

    border: false

    });

    return p;

    }

    // 中部 - 整体

    function getCenter() {

    // 按钮:上一步

    var btnPre = Ext.create("Ext.button.Button", {

    id: "btnPre",

    text: i18n_all.btn.pre,

    disabled: true,

    handler: function() {

    g_ix--;

    showPanel();

    }

    });

    // 按钮:下一步

    var btnNext = Ext.create("Ext.button.Button", {

    id: "btnNext",

    text: i18n_all.btn.next,

    handler: function() {

    g_ix++;

    showPanel();

    }

    });

    // 获取4个成员面板

    var p1 = getCenter01();

    var p2 = getCenter02();

    var p3 = getCenter03();

    var p4 = getCenter04();

    // 创建并返回卡片式布局面板

    var p =  Ext.create("Ext.panel.Panel", {

    id: "center1",

    layout: "card",

    title: i18n_my.title.test2_2,

    region: "center",

    items: [

    p1,

    p2,

    p3,

    p4

    ],

    buttons: [

    btnPre,

    btnNext

    ]

    });

    return p;

    }

    // 中部 - 第 1 个成员

    function getCenter01() {

    var tt = 1;

    var p =  Ext.create("Ext.panel.Panel", {

    title: Ext.String.format(i18n_all.title.guide, tt, "4"),

    html : Ext.String.format(i18n_my.msg.test2_2, tt),

    border: false

    });

    return p;

    }

    // 中部 - 第 2 个成员

    function getCenter02() {

    var tt = 2;

    var p =  Ext.create("Ext.panel.Panel", {

    title: Ext.String.format(i18n_all.title.guide, tt, "4"),

    html : Ext.String.format(i18n_my.msg.test2_2, tt),

    border: false

    });

    return p;

    }

    // 中部 - 第 3 个成员

    function getCenter03() {

    var tt = 3;

    var p =  Ext.create("Ext.panel.Panel", {

    title: Ext.String.format(i18n_all.title.guide, tt, "4"),

    html : Ext.String.format(i18n_my.msg.test2_2, tt),

    border: false

    });

    return p;

    }

    // 中部 - 第 4 个成员

    function getCenter04() {

    var tt = 4;

    var p =  Ext.create("Ext.panel.Panel", {

    title: Ext.String.format(i18n_all.title.guide, tt, "4"),

    html : Ext.String.format(i18n_my.msg.test2_2, tt),

    border: false

    });

    return p;

    }

    // 导航到某个面板

    function showPanel() {

    // 处理索引号,激活索引号对应的面板

    g_ix = g_ix<0?0:(g_ix>3?3:g_ix);

    Ext.getCmp("center1").getLayout().setActiveItem(g_ix);

    // 根据索引号,设置 上一步、下一步 按钮的可用性

    Ext.getCmp("btnPre").setDisabled(g_ix<=0);

    Ext.getCmp("btnNext").setDisabled(g_ix>=3);

    }

    4.3.2.3. 创建 /test02/test2.jsp文件

    <%@ page language="java" 

    contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>

    <%-- 共享文件 --%>

    <%@ include file="/common/imp.jsp"%>

    <%-- 本页面国际化JS文件 --%>

    <script src="${webRoot }/locale/test/test_${strLocale }.js"></script>

    <%-- 本页面功能JS文件 --%>

    <script src="${webRoot }/test02/test2.js"></script>

    4.3.2.4. 浏览

    浏览:http://localhost:8080/test/test02/test2.jsp

    1.初始时,显示的是card布局中第1个成员面板, 上一步 按钮被禁用

    2.点击 下一步 按钮后,显示第2个成员面板, 上一步、下一步按钮都被启用

    3.到第4步时,由于这是最后一个面板,所以 下一步 按钮被禁用


  • 相关阅读:
    FirstAFNetWorking
    JSONModel 简单例子
    KVO
    KVC
    关于UITableView的性能优化(历上最全面的优化分析)
    浅拷贝和深拷贝
    UI2_异步下载
    UI2_同步下载
    算法图解学习笔记02:递归和栈
    算法图解学习笔记01:二分查找&大O表示法
  • 原文地址:https://www.cnblogs.com/dyllove98/p/3143002.html
Copyright © 2020-2023  润新知