jQuery weui有个支持单选或者多选的select弹出层,默认他是这样的
第2部分选择什么值,第1部分就显示什么值,一般的场景支持是没问题了,但本次开发碰到了一个问题。
需求描述:
职业名称后面要显示一些描述,如“法官 2个案件在审理”,“医生 正在做手术”,同时要求点击对应项时,只显示“法官”,“医生”而不显示剩余的描述,根据select现有的逻辑是无法实现这个功能的。只能实现选项是什么,显示的值就是什么,不明白,看下图
解决方案:
查看官方文档,数据通过title和value进行控制,title是显示的值,value一般用于给后端传值
$("#mobile").select({
title: "选择职业",
items: [
{
title: "法官 2个案件在审理",
value: "001",
},
{
title: "医生 正在做手术",
value: "002",
}
]
});
很明显我们是可以通过修改items项的配置来实现该需求:
1、首先修改配置项
$("#mobile").select({
title: "选择职业",
items: [
{
title: "法官 2个案件在审理",
showTitle: "医生",
value: "001",
},
{
title: "医生 正在做手术",
showTitle: "医生",
value: "002",
}
]
});
showTitle用于回显
2、下面修改jquery.weui.js
大概从4695到4998行,Select组件封装在一个函数体中,这样避免变量污染同时也方便管理,大概有5个地方涉及到该需求,一个个来看:
2.1、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];
}
修改后的代码:
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];
}
新增了一个形参,同时对该形参进行了处理
原来的代码
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.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
根据文档我们知道data-values一般存储发送给后台的id值,用id值来做比较是最靠谱的,通过文本值来判断就未必了,多一个空格少个空格都不相等
2.3、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.4、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.5、defaults = $.fn.select.prototype.defaults配置项,此处要修改的是模板部分,修改如下:
toolbarTemplate: '\
{{#items}}\
\
{{/items}}\
',
checkboxTemplate:
'\
{{#items}}\
\
{{/items}}\
',
',
radioTemplate:
'
没什么特别的,只是给模板新增了一个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("" + config.toolbarTemplate + (config.multi ? config.checkboxTemplate : config.radioTemplate) + "");
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 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: '\
{{#items}}\
\
{{/items}}\
',
checkboxTemplate:
'\
{{#items}}\
\
{{/items}}\
',
}
}($);
',
radioTemplate:
'