jQuery weui Select組件顯示指定值

jQuery weui有個支持單選或者多選的select彈出層,默認他是這樣的javascript

第2部分選擇什麼值,第1部分就顯示什麼值,通常的場景支持是沒問題了,但本次開發碰到了一個問題。java

需求描述:jquery

職業名稱後面要顯示一些描述,如「法官 2個案件在審理」,「醫生 正在作手術」,同時要求點擊對應項時,只顯示「法官」,「醫生」而不顯示剩餘的描述,根據select現有的邏輯是沒法實現這個功能的。只能實現選項是什麼,顯示的值就是什麼,不明白,看下圖後端

解決方案:函數

查看官方文檔,數據經過title和value進行控制,title是顯示的值,value通常用於給後端傳值ui

$("#mobile").select({
  title: "選擇職業",
  items: [
    {
      title: "法官 2個案件在審理",
      value: "001",
    },
    {
      title: "醫生 正在作手術",
      value: "002",
    }
  ]
});

  

很明顯咱們是能夠經過修改items項的配置來實現該需求:this

一、首先修改配置項spa

$("#mobile").select({
    title: "選擇職業",
    items: [
        {
            title: "法官 2個案件在審理",
            showTitle: "醫生",
            value: "001",
        },
        {
            title: "醫生 正在作手術",
            showTitle: "醫生",
            value: "002",
        }
    ]
});

  

showTitle用於回顯

二、下面修改jquery.weui.js
大概從4695到4998行,Select組件封裝在一個函數體中,這樣避免變量污染同時也方便管理,大概有5個地方涉及到該需求,一個個來看:

2.一、Select.prototype.updateInputValue方法,該方法用於更新你點擊的那個input的值及給他設置一個data-values值,這裏有兩個地方須要修改
原來的代碼:
Select.prototype.updateInputValue = function(values, titles) {
    var v, t;
    if(this.config.multi) {
        v = values.join(this.config.split);
        t = titles.join(this.config.split);
    } else {
        v = values[0];
        t = titles[0];
    }

  修改後的代碼:prototype

Select.prototype.updateInputValue = function(values, titles, showtitles) {
    var v, t, s;
    if(this.config.multi) {
      v = values.join(this.config.split);
      t = titles.join(this.config.split);
      s = showtitles.join(this.config.split);
    } else {
      v = values[0];
      t = titles[0];
      s = showtitles[0];
    }

  新增了一個形參,同時對該形參進行了處理blog

原來的代碼

this.$input.val(t).data("values", v); 
this.$input.attr("value", t).attr("data-values", v);

  修改後的代碼

this.$input.val(s).data("values", v);
this.$input.attr("value", s).attr("data-values", v);

  能夠發現input的值再也不是原來的值,改爲了配置項showTitle的值

  2.二、Select.prototype.parseInitValue方法,該方法用於反顯,也就是你上次選值後再次調用select要把選中的部分給選上,整個方法更新以下:

Select.prototype.parseInitValue = function() {
    var value = this.$input.val();
    var items = this.config.items;
    var dataVales = this.$input.attr('data-values')

    //若是input爲空,只有在第一次初始化的時候才保留默認選擇。由於後來就是用戶本身取消了所有選擇,不能再爲他選中默認值。
    if( !this._init && (value === undefined || value == null || value === "")) return;

    var titles = this.config.multi ? value.split(this.config.split) : [value];
    var vals = this.config.multi ? dataVales.split(this.config.split) : [dataVales];

    // 建議以值來判斷哪些要處於選中狀態,以文原本判斷有太多不肯定因素,如值多了/少個空格
    if(vals || vals.length > 0) {
        for(var i=0;i<items.length;i++) {
            items[i].checked = false;
            for(var j=0;j<vals.length;j++) {
                if(parseInt(items[i].value) === parseInt(vals[j])) {
                    items[i].checked = true;
                }
            }
        }
    } else {
        for(var i=0;i<items.length;i++) {
            items[i].checked = false;
            for(var j=0;j<titles.length;j++) {
                if(items[i].title === titles[j]) {
                    items[i].checked = true;
                }
            }
        }
    }

  }

  根據文檔咱們知道data-values通常存儲發送給後臺的id值,用id值來作比較是最靠譜的,經過文本值來判斷就未必了,多一個空格少個空格都不相等

 

  2.三、Select.prototype._bind這是綁定事件的入口,總體修改以下:

Select.prototype._bind = function(dialog) {
    var self = this,
        config = this.config;
    dialog.on("change", function(e) {
      var checked = dialog.find("input:checked");
      var values = checked.map(function() {
        return $(this).val();
      });
      var titles = checked.map(function() {
        return $(this).data("title");
      });
      var showTitles = checked.map(function() {
          return $(this).data("showtitle");
      });

      self.updateInputValue(values, titles, showTitles);

      if(config.autoClose && !config.multi) self.close();
    })
    .trigger('change')
    .on("click", ".close-select", function() {
      self.close();
    });
  }

  做用就是給目標附加一個data-showtitle屬性,值就是配置項裏showTitle的值

 

  2.四、Select.prototype.getHTML該方法用於生成模板,修改以下:

Select.prototype.getHTML = function(callback) {
    var config = this.config;
    return this.tpl({
        items: config.items,
        title: config.title,
        showtitle: config.showTitle,
        closeText: config.closeText
    })
}

  依葫蘆畫瓢,新增了一個showtitle屬性,用於模板中顯示用

 

  2.五、defaults = $.fn.select.prototype.defaults配置項,此處要修改的是模板部分,修改以下:

toolbarTemplate: '<div class="toolbar">\
      <div class="toolbar-inner">\
      <a href="javascript:;" class="picker-button close-select">{{closeText}}</a>\
      <h1 class="title">{{title}}</h1>\
      </div>\
      </div>',
    radioTemplate:
      '<div class="weui-cells weui-cells_radio">\
        {{#items}}\
        <label class="weui-cell weui-check_label" for="weui-select-id-{{this.title}}">\
          <div class="weui-cell__bd weui-cell_primary">\
            <p>{{this.title}}</p>\
          </div>\
          <div class="weui-cell__ft">\
            <input type="radio" class="weui-check" name="weui-select" id="weui-select-id-{{this.title}}" value="{{this.value}}" {{#if this.checked}}checked="checked"{{/if}} data-showtitle="{{this.showTitle}}" data-title="{{this.title}}">\
            <span class="weui-icon-checked"></span>\
          </div>\
        </label>\
        {{/items}}\
      </div>',
    checkboxTemplate:
      '<div class="weui-cells weui-cells_checkbox">\
        {{#items}}\
        <label class="weui-cell weui-check_label" for="weui-select-id-{{this.title}}">\
          <div class="weui-cell__bd weui-cell_primary">\
            <p>{{this.title}}</p>\
          </div>\
          <div class="weui-cell__ft">\
            <input type="checkbox" class="weui-check" name="weui-select" id="weui-select-id-{{this.title}}" value="{{this.value}}" {{#if this.checked}}checked="checked"{{/if}} data-showtitle="{{this.showTitle}}" data-title="{{this.title}}" >\
            <span class="weui-icon-checked"></span>\
          </div>\
        </label>\
        {{/items}}\
      </div>',

  沒什麼特別的,只是給模板新增了一個data-showtitle屬性,用於回顯,到此整個修改完成,最後附完整代碼。

 

完整代碼:

+ function($) {
  "use strict";

  var defaults;

  var selects = [];

  var Select = function(input, config) {

    var self = this;
    this.config = config;

    //init empty data
    this.data = {
      values: '',
      titles: '',
      origins: [],
      length: 0
    };

    this.$input = $(input);
    this.$input.prop("readOnly", true);

    this.initConfig();

    config = this.config;

    this.$input.click($.proxy(this.open, this));
    selects.push(this)
  }

  Select.prototype.initConfig = function() {
    this.config = $.extend({}, defaults, this.config);

    var config = this.config;

    if(!config.items || !config.items.length) return;

    config.items = config.items.map(function(d, i) {
      if(typeof d == typeof "a") {
        return {
          title: d,
          value: d
        };
      }

      return d;
    });


    this.tpl = $.t7.compile("<div class='weui-picker-modal weui-select-modal'>" + config.toolbarTemplate + (config.multi ? config.checkboxTemplate : config.radioTemplate) + "</div>");

    if(config.input !== undefined) this.$input.val(config.input);

    this.parseInitValue();

    this._init = true;
  }

  Select.prototype.updateInputValue = function(values, titles, showtitles) {
    var v, t, s;
    if(this.config.multi) {
      v = values.join(this.config.split);
      t = titles.join(this.config.split);
      s = showtitles.join(this.config.split);
    } else {
      v = values[0];
      t = titles[0];
      s = showtitles[0];
    }

    //caculate origin data
    var origins = [];

    this.config.items.forEach(function(d) {
      values.each(function(i, dd) {
        if(d.value == dd) origins.push(d);
      });
    });

    // this.$input.val(t).data("values", v); // 原來的
    this.$input.val(s).data("values", v);
    // this.$input.attr("value", t).attr("data-values", v); // 原來的
    this.$input.attr("value", s).attr("data-values", v);

    var data = {
      values: v,
      titles: t,
      valuesArray: values,
      titlesArray: titles,
      origins: origins,
      length: origins.length
    };
    this.data = data;
    this.$input.trigger("change", data);
    this.config.onChange && this.config.onChange.call(this, data);
  }

  Select.prototype.parseInitValue = function() {
    var value = this.$input.val();
    var items = this.config.items;
    var dataVales = this.$input.attr('data-values')

    //若是input爲空,只有在第一次初始化的時候才保留默認選擇。由於後來就是用戶本身取消了所有選擇,不能再爲他選中默認值。
    if( !this._init && (value === undefined || value == null || value === "")) return;

    var titles = this.config.multi ? value.split(this.config.split) : [value];
    var vals = this.config.multi ? dataVales.split(this.config.split) : [dataVales];

    // 建議以值來判斷哪些要處於選中狀態,以文原本判斷有太多不肯定因素,如值多了/少個空格
    if(vals || vals.length > 0) {
        for(var i=0;i<items.length;i++) {
            items[i].checked = false;
            for(var j=0;j<vals.length;j++) {
                if(parseInt(items[i].value) === parseInt(vals[j])) {
                    items[i].checked = true;
                }
            }
        }
    } else {
        for(var i=0;i<items.length;i++) {
            items[i].checked = false;
            for(var j=0;j<titles.length;j++) {
                if(items[i].title === titles[j]) {
                    items[i].checked = true;
                }
            }
        }
    }

  }

  Select.prototype._bind = function(dialog) {
    var self = this,
        config = this.config;
    dialog.on("change", function(e) {
      var checked = dialog.find("input:checked");
      var values = checked.map(function() {
        return $(this).val();
      });
      var titles = checked.map(function() {
        return $(this).data("title");
      });
      var showTitles = checked.map(function() {
          return $(this).data("showtitle");
      });

      self.updateInputValue(values, titles, showTitles);

      if(config.autoClose && !config.multi) self.close();
    })
    .trigger('change')
    .on("click", ".close-select", function() {
      self.close();
    });
  }

  //更新數據
  Select.prototype.update = function(config) {
    this.config = $.extend({}, this.config, config);
    this.initConfig();
    if(this._open) {
      this._bind($.updatePicker(this.getHTML()));
    }
  }

  Select.prototype.open = function(values, titles) {

    if(this._open) return;

    // open picker 會默認關掉其餘的,可是 onClose 不會被調用,因此這裏先關掉其餘select
    for (var i = 0; i < selects.length; i++ ) {
      var s = selects[i];
      if (s === this) continue;
      if (s._open) {
        if(!s.close()) return false; // 其餘的select因爲某些條件限制關閉失敗。
      }
    }

    this.parseInitValue();

    var config = this.config;

    var dialog = this.dialog = $.openPicker(this.getHTML());

    this._bind(dialog);

    this._open = true;
    if(config.onOpen) config.onOpen(this);
  }

  Select.prototype.close = function(callback, force) {
    if (!this._open) return false;
    var self = this,
        beforeClose = this.config.beforeClose;

    if(typeof callback === typeof true) {
      force === callback;
    }
    if(!force) {
      if(beforeClose && typeof beforeClose === 'function' && beforeClose.call(this, this.data.values, this.data.titles) === false) {
        return false
      }
      if(this.config.multi) {
        if(this.config.min !== undefined && this.data.length < this.config.min) {
          $.toast("請至少選擇"+this.config.min+"個", "text");
          return false
        }
        if(this.config.max !== undefined && this.data.length > this.config.max) {
          $.toast("最多隻能選擇"+this.config.max+"個", "text");
          return false
        }
      }
    }
    $.closePicker(function() {
      self.onClose();
      callback && callback();
    });

    return true
  }

  Select.prototype.onClose = function() {
    this._open = false;
    if(this.config.onClose) this.config.onClose(this);
  }

  Select.prototype.getHTML = function(callback) {
    var config = this.config;
    return this.tpl({
      items: config.items,
      title: config.title,
        showtitle: config.showTitle,
      closeText: config.closeText
    })
  }


  $.fn.select = function(params, args) {

    return this.each(function() {
      var $this = $(this);
      if(!$this.data("weui-select")) $this.data("weui-select", new Select(this, params));

      var select = $this.data("weui-select");

      if(typeof params === typeof "a") select[params].call(select, args);

      return select;
    });
  }

  defaults = $.fn.select.prototype.defaults = {
    items: [],
    input: undefined, //輸入框的初始值
    title: "請選擇",
    multi: false,
    closeText: "肯定",
    autoClose: true, //是否選擇完成後自動關閉,只有單選模式下才有效
    onChange: undefined, //function
    beforeClose: undefined, // function 關閉以前,若是返回false則阻止關閉
    onClose: undefined, //function
    onOpen: undefined, //function
    split: ",",  //多選模式下的分隔符
    min: undefined, //多選模式下可用,最少選擇數
    max: undefined, //單選模式下可用,最多選擇數
    toolbarTemplate: '<div class="toolbar">\
      <div class="toolbar-inner">\
      <a href="javascript:;" class="picker-button close-select">{{closeText}}</a>\
      <h1 class="title">{{title}}</h1>\
      </div>\
      </div>',
    radioTemplate:
      '<div class="weui-cells weui-cells_radio">\
        {{#items}}\
        <label class="weui-cell weui-check_label" for="weui-select-id-{{this.title}}">\
          <div class="weui-cell__bd weui-cell_primary">\
            <p>{{this.title}}</p>\
          </div>\
          <div class="weui-cell__ft">\
            <input type="radio" class="weui-check" name="weui-select" id="weui-select-id-{{this.title}}" value="{{this.value}}" {{#if this.checked}}checked="checked"{{/if}} data-showtitle="{{this.showTitle}}" data-title="{{this.title}}">\
            <span class="weui-icon-checked"></span>\
          </div>\
        </label>\
        {{/items}}\
      </div>',
    checkboxTemplate:
      '<div class="weui-cells weui-cells_checkbox">\
        {{#items}}\
        <label class="weui-cell weui-check_label" for="weui-select-id-{{this.title}}">\
          <div class="weui-cell__bd weui-cell_primary">\
            <p>{{this.title}}</p>\
          </div>\
          <div class="weui-cell__ft">\
            <input type="checkbox" class="weui-check" name="weui-select" id="weui-select-id-{{this.title}}" value="{{this.value}}" {{#if this.checked}}checked="checked"{{/if}} data-showtitle="{{this.showTitle}}" data-title="{{this.title}}" >\
            <span class="weui-icon-checked"></span>\
          </div>\
        </label>\
        {{/items}}\
      </div>',
  }

}($);
相關文章
相關標籤/搜索