• JavaScript封装一个实用的select控件


      最近一直把精力放在项目上面,导致忽略的一些底层的东西。以前就一直觉得原有的select控件很丑,正好周末有时间,试着做了一个简单封装,实现了它的基本功能。我总结了一下,大概分为三个部分:

      1、对显示样式的处理

      2、对点击和hover事件的处理

      3、change事件发送请求的处理

      我们先看jsp的展示代码:

    <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
    <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
          <style>
              .hide{display:none}
              .mySelect{position:relative;}
            .ms_div{height:33px;line-height:33px;width:220px;display:inline-block;border:1px solid #ddd;
                border-right:0;cursor:pointer;border-radius:3px;}
            ms_op{display:block;line-height:33px;margin-bottom:1px;}
            .ms_div .ms_label:before,.ms_div ms_op:before{content:" "}
            ms_op:hover{color:rgb(1%,60%,80%)}
            .ms_btn{position:absolute;width:20px;height:100%;display:block;top:0px;right:0px;
                text-align:center;color:#fff;z-index:3;line-height:35px;background: rgb(10%,65%,85%);}
            .ms_op_div{position:absolute;top:34px;left:0;width:100%;z-index:4;}
            .ms_op_con{max-height:400px;overflow-y:auto;border-bottom:1px solid #ddd;background:#fff;
                border-right:1px solid #eee;padding-bottom:5px;font-weight:nomal;color:#666;border-left:1px solid #ddd;}
            .showDiv{padding-top:30px}
          </style>
          <script type="text/javascript" src="<c:url value='/res/js/jquery.js'/>"></script>
          <script>
              $.fn.extend({
                changeClass:function(flag,removeFlag,class1,class2) {
                 if(removeFlag) return this.removeClass(class1).removeClass(class2);
                 return this.addClass(flag?class1:class2).removeClass(flag?class2:class1);
                },
                addOrRemoveClass:function(flag,className){
                    if(flag) return this.addClass(className);
                    return this.removeClass(className);
                },
                switchClass:function(className){
                    if(this.hasClass(className)) return this.removeClass(className);
                    return this.addClass(className);
                },
                switchClass2:function(class1,class2){
                    if(this.hasClass(class1)) return this.removeClass(class1).addClass(class2);
                    return this.removeClass(class2).addClass(class1);
                },
                replaceClass:function(class1,class2){
                    return this.removeClass(class2).addClass(class1);
                }
            });
          </script>
          <script type="text/javascript" src="<c:url value='/res/js/MySelect.js'/>"></script>
      </head>
          <div class="selectDiv"></div>
          <div class="showDiv"></div>
          <script>    
              $(function(){
                  var $showDiv = $(".showDiv");
                  var orgTypeMap={"j":"集团","b":"银行","a":"合作方","m":"商户","":"--请选择机构类型--"};
                  var changeHandler = function(id,value){
                      //回调函数,这里可以拿到当前选中的option的id和value
                      var url = "";
                      var param = {};
                      param.id = id;
                      $.post("<c:url value='/sys/selectQueryData'/>",param,function(data){
                          //把后台发送的数据显示到页面
                          if(!data.success=="success") alert("请求数据出错");
                          $showDiv.html(data.msg);
                      },"json")
                  }
                  //new一个MySelect对象,执行createByData和change方法,这两个方法是必须在这里执行的
                  new MySelect($(".selectDiv"),"id","").createByData(orgTypeMap).change(changeHandler);
                  
                  
              })
          </script>
      <body>
        
      </body>
    </html>

      引入MySelect.js文件,不要忘了在之前先要引入jquery.js,因为这个使用了jquery的方法。上面我对$做了几个方法的扩展,其中用到了switchClass方法,这样要比单独写一个文件方便的多。

      MySelect.js的代码如下:

    function MySelect($selectDiv,fildName,defaultValue){
        this.defaultValue = defaultValue;
        this.$selectDiv = $selectDiv.addClass("mySelect");
        this.$selectBtn = $("<span class='ms_btn'>▼</span>");
        this.$optionsDiv=$("<div class='ms_op_div hide'></div>");
        this.$optionConDiv=$("<div class='ms_op_con'></div>").appendTo(this.$optionsDiv);
        this.$selectLabel=$("<span class='ms_label'></span>");
        this.$hiddenInput=$("<input type='hidden' name='"+fildName+"' value='"+this.defaultValue+"'></input>");
        this.changeHandler=$.noop;
        this.init();
    }
    //将回调函数changeHandler赋值给MySelect的函数
    MySelect.prototype.change = function(changeHandler){
        this.changeHandler = changeHandler;
        return this;
    }
    //初始化select,我在里面定义了一个hover事件
    MySelect.prototype.init = function(){
        if(!this.$selectDiv||this.$selectDiv.length==0){
            alert("初始化容器失败!");
            return;
        }
        this.$selectDiv.addClass("ms_div").append(this.$selectLabel).append(this.$hiddenInput);
        var ch=null;
        var self = this;
        this.$optionsDiv.hover(function(e){
                e.stopPropagation();
                if(ch!=null) clearTimeout(ch);
            },function(e){
                e.stopPropagation();
                var t=this;
                ch=setTimeout(function(){
                    $(t).addClass("hide");
                },500);
            });
        return this;
    }
    //根据用户提供的map对象创建select的option数据
    MySelect.prototype.createByData=function(data){
        var cn="";
        for(var key in data){
            var value=data[key];
            this.addOption(key,value,cn);
        }
        this.fill();
        return this;
    }
    //设置默认显示的option,把数据填充到已经创建好的$optionConDiv里面
    MySelect.prototype.addOption=function(key,value,cn){
        if(key==this.defaultValue){
            cn="ms_op_cur";
            this.$selectLabel.html(value);
        }
        $("<ms_op value='"+key+"'>"+value+"</ms_op>").addClass(cn).appendTo(this.$optionConDiv);
    }
    //设置选中的option
    MySelect.prototype.setCurValue = function(key,value){
        this.$selectLabel.html(value);
        this.$hiddenInput.val(key);
    }
    //定义select的点击事件,如果nodeName是option,就执行setCurValue和回调函数
    MySelect.prototype.click=function(e){
        var t=e.target;
        var n=t.nodeName;
        this.$optionsDiv.switchClass("hide");
        if (n == 'MS_OP') {
            if($(t).hasClass("ms_op_cur")) return;
            $(t).addClass("ms_op_cur").siblings(".ms_op_cur").removeClass("ms_op_cur");
            this.setCurValue(t.getAttribute("value"), t.textContent);
            this.changeHandler(t.getAttribute("value"),t.textContent);
        }
    }
    //fill函数是在select对象调用createByData时候执行的,这里使用了事件代理完成了对$selectDiv的click事件操作
    MySelect.prototype.fill=function(){
        this.$selectDiv.append(this.$selectBtn).append(this.$optionsDiv);
        this.$selectDiv.click($.proxy(this.click,this));
    }

      根据上面代码,页面初步的展示如图:

      下一步,我们需要编写后台代码来响应change事件的请求:

    package cn.wangze.servlet;
    
    
    import java.io.IOException;
    import java.io.PrintWriter;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class MySelectServlet extends HttpServlet{
        public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
            PrintWriter out = response.getWriter();
            String id = request.getParameter("id");
            if("j".equals(id)){
                out.println("这里返回集团的数据....");
            }
            if("b".equals(id)){
                out.println("这里返回银行的数据....");
            }
            if("a".equals(id)){
                out.println("这里返回合作方的数据....");
            }
            if("m".equals(id)){
                out.println("这里返回商户的数据....");
            }
        }
    }

      根据前台传的id不同,做出不同的回应。实际应用中肯定会复杂很多,我这里只是简单的演示一下。

      代码部分就是上面展示的这些,我们看一下最后完成的效果:

      因为"--请选择机构类型--"对应的id我们没有设置,后台也没有处理,所以response没有返回值,其他设置过的返回数据都是正常了。

      我觉得封装这些小控件非常考验js的基础掌握能力,对个人的技术水平有一定程度的锻炼,我们现在做项目都是找到好用的插件随手拿来就用,但是里面底层的只是估计很难讲清楚。很多人都是知道怎么用。但是不知道为什么这么用,自己封装就不同了,第一可以更灵活的使用它,第二哪里出了问题不会一脸懵,第三可根据业务作出扩展或者修改。

        当然,这些都是在时间富裕的前提下说的,如果每天工作的事情都做不完,哪里还有时间自己造轮子,所以业余时间的的分配很能够考验一个人的职业水平。

      说的再多,不如自己动手操作,毕竟实践出真知嘛。

  • 相关阅读:
    短视频直播源码开发,防抖和节流的区别和实用场景
    游戏陪玩平台源码开发,语音通话中的噪音消除处理
    语音聊天室源码开发,如何实现回音消除功能?
    【代码解析】双向链表实现贪吃蛇游戏!简单易学,开发自己第一个游戏!
    程序员偷偷去面试,上班时却没发现身上还有其他公司的访客贴!
    编程语言年度观赏大戏,来看看内部撕X,你站谁?
    数组倒序排列,数组倒置,C语言数组倒序算法详解!
    编程领域这些禁术相当精彩,掌握其一,方可修炼编程大法!
    无处不在的网络编程,到底是如何工作的?今天我们一探究竟!
    【编程黑科技】gethostbyname()函数:通过域名获取IP地址!
  • 原文地址:https://www.cnblogs.com/blue-wz/p/7467429.html
Copyright © 2020-2023  润新知