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<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.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: '<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>',
- }
- }($);
来源: https://www.cnblogs.com/diantao/p/10299936.html