easyui之combo控件分析

/**
 * combo - jQuery EasyUI
 * 
 * Licensed under the GPL:
 *   http://www.gnu.org/licenses/gpl.txt
 *
 * Copyright 2010 stworthy [ stworthy@gmail.com ] 
 * 
 * Dependencies:
 *   panel
 *   validatebox
 * 
 */
/**
 * 首先combo控件的组成:
 * <span.combo>
 *     <input.combo-text><!--接收用户输入-->
 *     <span><!--盛放下来箭头-->
 *         <span.combo-arrow>
 *     <input.combo-value><!--真正用来存放数据值的隐藏框-->
 *
 */
(function($){
   function setSize(target, width){
      var opts = $.data(target, 'combo').options;
      var combo = $.data(target, 'combo').combo;
      var panel = $.data(target, 'combo').panel;
      
      if (width) opts.width = width;
      
      if (isNaN(opts.width)){
         opts.width = combo.find('input.combo-text').outerWidth();
      }
      var arrowWidth = combo.find('.combo-arrow').outerWidth();
      var width = opts.width - arrowWidth;
      combo.find('input.combo-text').width(width);
      
      panel.panel('resize', {
         width: (opts.panelWidth ? opts.panelWidth : combo.outerWidth()),
         height: opts.panelHeight
      });
   }
   
   /**
    * create the combo component.
    */
   function init(target){
      //首先将原来绑定的元素隐藏
      $(target).hide();

      //在原来的元素后面添加span标签,这个标签作为combo控件的最外层元素
      var span = $('<span class="combo"></span>').insertAfter(target);
      //在最外层span标签里添加一个input作为用户的输入框
      var input = $('<input type="text" class="combo-text">').appendTo(span);
      //在最外层span标签里添加一个span作为下拉箭头
      $('<span><span class="combo-arrow"></span></span>').appendTo(span);
      //在最外层span标签里添加一个隐藏的input标签
      $('<input type="hidden" class="combo-value">').appendTo(span);
      //combo控件的下拉面板直接添加到body里面
      var panel = $('<div class="combo-panel"></div>').appendTo('body');
      //将下拉面板隐藏起来并且其他的设置
      panel.panel({
         doSize:false,
         closed:true,
         style:{
            position:'absolute'
         },
         onOpen:function(){
            $(this).panel('resize');
         }
      });
      
      var name = $(target).attr('name');
      if (name){
         //如果用户指定的元素上存在name属性,那么就将这个name属性设置到combo控件中隐藏的input标签内,并且将原来用户指定元素的name属性名称切换为comboname
         span.find('input.combo-value').attr('name', name);
         $(target).removeAttr('name').attr('comboName', name);
      }
      input.attr('autocomplete', 'off');
      
      return {
         combo: span,
         panel: panel
      };
   }
   
   function destroy(target){
      //销毁combo控件,就是从dom中移除掉元素
      $.data(target, 'combo').panel.panel('destroy');
      $.data(target, 'combo').combo.remove();
      $(target).remove();
   }
   
   function bindEvents(target){
      var opts = $.data(target, 'combo').options;
      var combo = $.data(target, 'combo').combo;
      var panel = $.data(target, 'combo').panel;
      var input = combo.find('.combo-text');
      var arrow = combo.find('.combo-arrow');
      //首先解绑combo对象的所有combo事件
      $(document).unbind('.combo');
      combo.unbind('.combo');
      panel.unbind('.combo');
      input.unbind('.combo');
      arrow.unbind('.combo');
      
      if (!opts.disabled){
         //一旦用户点击了其他地方的任意区域,所有下拉框的面板就要折叠
         $(document).bind('mousedown.combo', function(e){
            $('div.combo-panel').panel('close');
         });
         //
         panel.bind('mousedown.combo', function(e){
            return false;
         });
         //一旦combo的输入框聚焦后,就要显示下拉框面板
         input.bind('focus.combo', function(){
            showPanel(target);
         }).bind('mousedown.combo', function(e){
            e.stopPropagation();
         }).bind('keyup.combo', function(e){
            //下拉框中关于"上下左右键"的操作
            switch(e.keyCode){
               case 37:   // left
               case 38:   // up
                  opts.selectPrev.call(target);
                  break;
               case 39:   // right
               case 40:   // down
                  opts.selectNext.call(target);
                  break;
               case 13:   // enter
                  opts.selectCurr.call(target);
                  break;
               case 27:   // esc
                  hidePanel(target);
                  break;
               default:
                  if (opts.editable){
                     opts.filter.call(target, $(this).val());
                  }
            }
            return false;
         });
         
         arrow.bind('click.combo', function(){
            //点击箭头,这里出发输入框聚焦,而输入框的聚焦又可以使下拉框面板展示
            input.focus();
         }).bind('mouseenter.combo', function(){
            $(this).addClass('combo-arrow-hover');
         }).bind('mouseleave.combo', function(){
            $(this).removeClass('combo-arrow-hover');
         });
      }
   }
   
   /**
    * show the drop down panel.
    */
   function showPanel(target){
      var combo = $.data(target, 'combo').combo;
      var panel = $.data(target, 'combo').panel;
      
      if ($.fn.window){
         panel.panel('panel').css('z-index', $.fn.window.defaults.zIndex++);
      }
      
      panel.panel('open');
      
      (function(){
         if (panel.is(':visible')){
            var top = combo.offset().top + combo.outerHeight();
            if (top + panel.outerHeight() > $(window).height() + $(document).scrollTop()){
               top = combo.offset().top - panel.outerHeight();
            }
            if (top < $(document).scrollTop()){
               top = combo.offset().top + combo.outerHeight();
            }
            panel.panel('move', {
               left:combo.offset().left,
               top:top
            });
            setTimeout(arguments.callee, 200);
         }
      })();
   }
   
   /**
    * hide the drop down panel.
    */
   function hidePanel(target){
      var panel = $.data(target, 'combo').panel;
      panel.panel('close');
   }
   
   function validate(target, doit){
      if ($.fn.validatebox){
         var opts = $.data(target, 'combo').options;
         var input = $.data(target, 'combo').combo.find('input.combo-text');
         input.validatebox(opts);
         if (doit){
            input.validatebox('validate');
            input.trigger('mouseleave');
         }
      }
   }
   
   function setDisabled(target, disabled){
      var opts = $.data(target, 'combo').options;
      var combo = $.data(target, 'combo').combo;
      if (disabled){
         opts.disabled = true;
         $(target).attr('disabled', true);
         combo.find('.combo-value').attr('disabled', true);
         combo.find('.combo-text').attr('disabled', true);
      } else {
         opts.disabled = false;
         $(target).removeAttr('disabled');
         combo.find('.combo-value').removeAttr('disabled');
         combo.find('.combo-text').removeAttr('disabled');
      }
   }
   
   function clear(target){
      var combo = $.data(target, 'combo').combo;
      combo.find('input.combo-value:gt(0)').remove();
      combo.find('input.combo-value').val('');
      combo.find('input.combo-text').val('');
   }
   
   function getText(target){
      var combo = $.data(target, 'combo').combo;
      return combo.find('input.combo-text').val();
   }
   
   function setText(target, text){
      var combo = $.data(target, 'combo').combo;
      combo.find('input.combo-text').val(text);
      validate(target, true);
   }
   
   function getValues(target){
      var values = [];
      var combo = $.data(target, 'combo').combo;
      combo.find('input.combo-value').each(function(){
         values.push($(this).val());
      });
      return values;
   }
   
   function setValues(target, values){
      var opts = $.data(target, 'combo').options;
      var oldValues = getValues(target);
      
      var combo = $.data(target, 'combo').combo;
      combo.find('input.combo-value').remove();
      var name = $(target).attr('comboName');
      for(var i=0; i<values.length; i++){
         var input = $('<input type="hidden" class="combo-value">').appendTo(combo);
         if (name) input.attr('name', name);
         input.val(values[i]);
      }
      
      var tmp = [];
      for(var i=0; i<oldValues.length; i++){
         tmp[i] = oldValues[i];
      }
      var aa = [];
      for(var i=0; i<values.length; i++){
         for(var j=0; j<tmp.length; j++){
            if (values[i] == tmp[j]){
               aa.push(values[i]);
               tmp.splice(j, 1);
               break;
            }
         }
      }
      
      if (aa.length != values.length || values.length != oldValues.length){
         if (opts.multiple){
            opts.onChange.call(target, values, oldValues);
         } else {
            opts.onChange.call(target, values[0], oldValues[0]);
         }
      }
   }
   
   function getValue(target){
      var values = getValues(target);
      return values[0];
   }
   
   function setValue(target, value){
      setValues(target, [value]);
   }
   
   /**
    * parse options from markup.
    */
   function parseOptions(target){
      var t = $(target);
      return {
         width: (parseInt(target.style.width) || undefined),
         panelWidth: (parseInt(t.attr('panelWidth')) || undefined),
         panelHeight: (t.attr('panelHeight')=='auto' ? 'auto' : parseInt(t.attr('panelHeight')) || undefined),
         separator: (t.attr('separator') || undefined),
         multiple: (t.attr('multiple') ? (t.attr('multiple') == 'true' || t.attr('multiple') == true) : undefined),
         editable: (t.attr('editable') ? t.attr('editable') == 'true' : undefined),
         disabled: (t.attr('disabled') ? true : undefined),
         required: (t.attr('required') ? (t.attr('required') == 'true' || t.attr('required') == true) : undefined),
         missingMessage: (t.attr('missingMessage') || undefined)
      };
   }
   
   $.fn.combo = function(options, param){
      //如果是字符串就是在调用方法,方法的参数比较集中放在了fombo.methods里面
      if (typeof options == 'string'){
         return $.fn.combo.methods[options](this, param);
      }
      
      options = options || {};
      return this.each(function(){
         var state = $.data(this, 'combo');
         if (state){
            $.extend(state.options, options);
         } else {
            //初始化combo
            var r = init(this);
            state = $.data(this, 'combo', {
               options: $.extend({}, $.fn.combo.defaults, parseOptions(this), options),
               combo: r.combo,
               panel: r.panel
            });
            $(this).removeAttr('disabled');
         }
         $('input.combo-text', state.combo).attr('readonly', !state.options.editable);
         setDisabled(this, state.options.disabled);
         setSize(this);
         bindEvents(this);
         validate(this);
      });
   };
   
   $.fn.combo.methods = {
      parseOptions: function(jq){
         return parseOptions(jq[0]);
      },
      options: function(jq){
         return $.data(jq[0], 'combo').options;
      },
      panel: function(jq){
         return $.data(jq[0], 'combo').panel;
      },
      textbox: function(jq){
         return $.data(jq[0], 'combo').combo.find('input.combo-text');
      },
      destroy: function(jq){
         return jq.each(function(){
            destroy(this);
         });
      },
      resize: function(jq, width){
         return jq.each(function(){
            setSize(this, width);
         });
      },
      showPanel: function(jq){
         return jq.each(function(){
            showPanel(this);
         });
      },
      hidePanel: function(jq){
         return jq.each(function(){
            hidePanel(this);
         });
      },
      disable: function(jq){
         return jq.each(function(){
            setDisabled(this, true);
            bindEvents(this);
         });
      },
      enable: function(jq){
         return jq.each(function(){
            setDisabled(this, false);
            bindEvents(this);
         });
      },
      clear: function(jq){
         return jq.each(function(){
            clear(this);
         });
      },
      getText: function(jq){
         return getText(jq[0]);
      },
      setText: function(jq, text){
         return jq.each(function(){
            setText(this, text);
         });
      },
      getValues: function(jq){
         return getValues(jq[0]);
      },
      setValues: function(jq, values){
         return jq.each(function(){
            setValues(this, values);
         });
      },
      getValue: function(jq){
         return getValue(jq[0]);
      },
      setValue: function(jq, value){
         return jq.each(function(){
            setValue(this, value);
         });
      }
   };
   
   $.fn.combo.defaults = {
      width: 'auto',
      panelWidth: null,
      panelHeight: 200,
      multiple: false,
      separator: ',',
      editable: true,
      disabled: false,
      required: false,
      missingMessage: 'This field is required.',
      
      selectPrev: function(){},
      selectNext: function(){},
      selectCurr: function(){},
      filter: function(query){},
      
      onChange: function(newValue, oldValue){}
   };
})(jQuery);
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jackletter

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值