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>', } }($);