实现代码 html 结构布局部分:
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <style> div, input { padding: 0; margin: 0 } ul, li { list-style: none; margin: 0; padding: 0; } .displayNone { display: none; } .again, .group { height: 32px; padding: 0 4px; margin: 2px; background-color: #c3c3c3; border: 1px solid #333; border-radius: 5px; box-shadow: none; outline: none; cursor: pointer; } .again:hover, .group:hover { background-color: #c3f1f8; } /*多项 选择和删除 弹出框 样式布局*/ .jd_widget_box * { margin: 0; padding: 0; font-size: 12px; font-family: "Microsoft YaHei", 微软雅黑, "Microsoft JhengHei", 华文细黑, STHeiti, MingLiu; color: #464c5b; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; -webkit-text-size-adjust: none; } .jd_widget_box .jd_pop_box { width: 100%; height: 100%; position: fixed; top: 0; left: 0; z-index: 999; } /*弹出框背景色*/ .jd_widget_box .jd_pop_bg { width: 100%; height: 100%; position: fixed; top: 0; left: 0; background-color: #767779; opacity: .7; filter: alpha(opacity=70); z-index: 990; } .jd_widget_box .result_input { box-sizing: border-box; height: 32px; line-height: 32px; padding: 0 4px; vertical-align: middle; border: 1px solid #333; border-radius: 3px; box-shadow: none; outline: none; } .jd_widget_box .result_box { box-sizing: border-box; display: inline-block; vertical-align: middle; } .jd_widget_box .btn_add { box-sizing: border-box; width: 32px; height: 32px; margin: 0 2px; vertical-align: middle; background-color: #fff; border: 1px solid #333; border-radius: 3px; box-shadow: none; outline: none; cursor: pointer; } .jd_widget_box .btn_add:hover { background-color: #c3f1f8; } .jd_widget_box .jd_show_box { width: 690px; height: 400px; position: absolute; left: 50%; top: 50%; margin-left: -345px; margin-top: -200px; background-color: #f7f7f7; opacity: 1; border: 1px solid #ddd; border-radius: 3px; z-index: 999; } .jd_widget_box .jd_top_bar { box-sizing: border-box; width: 100%; height: 38px; line-height: 38px; padding: 0 10px; font-size: 14px; font-weight: 600; border-bottom: 1px solid #e4e9ed; } .jd_widget_box .btn_submit { float: right; height: 24px; padding: 0 18px; color: #fff; background-color: #4b71c2; border: 1px solid #2e5abd; border-radius: 3px; box-shadow: none; outline: none; cursor: pointer; } .jd_widget_box .btn_close { float: right; width: 16px; height: 16px; margin: 11px auto; background: url("css/widgeticon/closeTab.png") left center no-repeat; background-size: cover; cursor: pointer; } .jd_widget_box .filter_box { box-sizing: border-box; width: 100%; padding: 20px 30px 15px 20px; } .jd_widget_box .filter_input { box-sizing: border-box; width: 325px; height: 24px; padding: 0 8px; border: 1px solid #8fb7e6; border-radius: 3px; } .jd_widget_box .btn_tools { display: inline-block; width: 345px; padding-left: 30px; box-sizing: border-box } /*全选,全不选按钮*/ .jd_widget_box .btn_selected_all, .jd_widget_box .btn_unselected_all { line-height: 20px; padding: 0; background-color: transparent; border: none; border-radius: 3px; box-shadow: none; outline: none; } /*全选图标*/ .jd_widget_box .btn_selected_all .icon_select_all { float: left; width: 20px; height: 20px; margin-right: 6px; background: url("css/widgeticon/select_icon_show.png") left center no-repeat; cursor: pointer; } /*全不选图标*/ .jd_widget_box .icon_unselect_all { float: left; width: 20px; height: 20px; margin-right: 6px; background: url("css/widgeticon/delete_icon_show.png") left center no-repeat; cursor: pointer; } .jd_widget_box .icon_select_all:hover { background: url("css/widgeticon/select_icon_hover.png") left center no-repeat; } .jd_widget_box .icon_select_all:active { background: url("css/widgeticon/select_icon_active.png") left center no-repeat; } .jd_widget_box .icon_unselect_all:hover { background: url("css/widgeticon/delete_icon_hover.png") left center no-repeat; } .jd_widget_box .icon_unselect_all:active { background: url("css/widgeticon/delete_icon_active.png") left center no-repeat; } /*显示共选择则数量*/ .jd_widget_box .count_text { display: inline-block; width: 120px; padding-right: 8px; margin-left: 40px; text-align: right; } /*筛选 和 已选 列表项*/ .jd_widget_box .box_items { box-sizing: border-box; width: 688px; padding: 12px 0; } .jd_widget_box .filter_list, .jd_widget_box .selected_list { display: inline-block; width: 335px; height: 248px; overflow: auto } .jd_widget_box .filter_list li, .jd_widget_box .selected_list li { box-sizing: border-box; padding: 0 0 0 30px; line-height: 28px; border-bottom: none; } .jd_widget_box .filter_list { margin-right: 10px; } .jd_widget_box .filter_list li:hover, .jd_widget_box .selected_list li:hover { background-color: #f3f3f3; cursor: pointer; } /*筛选条件列表的添加图标*/ .jd_widget_box .filter_list li .icon_select_list { float: left; width: 20px; height: 20px; padding: 4px 0; margin-right: 6px; vertical-align: text-bottom; } .jd_widget_box .filter_list li:hover .icon_select_list { background: url("css/widgeticon/select_icon_show.png") left center no-repeat; } .jd_widget_box .filter_list li:hover .icon_select_list:hover { background: url("css/widgeticon/select_icon_hover.png") left center no-repeat; } .jd_widget_box .filter_list li:hover .icon_select_list:active { background: url("css/widgeticon/select_icon_active.png") left center no-repeat; } /*已选列表的删除图标*/ .jd_widget_box .selected_list li .icon_unselect_list { float: left; width: 20px; height: 20px; padding: 4px 0; margin-right: 6px; vertical-align: text-bottom; } /*已选列表的删除图标*/ .jd_widget_box .selected_list li:hover .icon_unselect_list { background: url("css/widgeticon/delete_icon_show.png") left center no-repeat; } .jd_widget_box .selected_list li:hover .icon_unselect_list:hover { background: url("css/widgeticon/delete_icon_hover.png") left center no-repeat; } .jd_widget_box .selected_list li:hover .icon_unselect_list:active { background: url("css/widgeticon/delete_icon_active.png") left center no-repeat; } /*显示已选中的按钮组*/ .jd_widget_box .item_card { display: inline-block; box-sizing: border-box; height: 32px; line-height: 32px; padding: 0 35px; margin: 0 2px; position: relative; text-align: center; background: #fff; border: 1px solid #666666; border-radius: 3px; outline: none; cursor: pointer; } .jd_widget_box .item_card:hover { background-color: #eff4f9; border: 1px solid #8fb7e6; } .jd_widget_box .item_card:hover .btn_small_del { display: inline-block; width: 10px; height: 10px; position: absolute; right: 5px; top: 5px; font-size: 18px; font-weight: 500; cursor: pointer; background: url('css/widgeticon/close-small.png') center center no-repeat; } </style> </head> <body> <div id="maincontainer"> </div> <input class="again" type="button" value="Again" οnclick="doCreate()"/> <script src="js/jquery-1.11.3.js"></script> <script src="js/jquery-ui.js"></script> <script src="js/a-widget.js"></script> <script> var xx; // 显示的是id 卡片组 function doCreate() { $('#maincontainer').multiSelect({ id: "t", items: [ {id: 'k001', name: '这是文本一'}, {id: 'k002', name: '这是文本二', selected: true}, {id: 'k003', name: '这是文本三'}, {id: 'k004', name: '这是文本四'}, {id: 'k005', name: '这是文本五'}, {id: 'k006', name: '这是文本6', selected: true}, {id: 'k007', name: '这是文本7'}, {id: 'k008', name: '这是文本8'}, {id: 'k009', name: '这是文本9'}, {id: 'k0010', name: '这是文本10'}, {id: 'k0011', name: '这是文本11'}, {id: 'k0012', name: '这是文本12'}, {id: 'k0013', name: '这是文本13'}, {id: 'k0014', name: '这是文本14'} ], selecteds: [ 'k003' ], excludes: [ 'k003', 'k004', 'k005' ], maxShowCount: 2, style: 1, showType: 0, maxShowFormat: "我选了{0}个共{1}", complete: function (event, data) { $.each(data, function (i, val) { }) }, deleted: function (event, data) { alert("删除的ID: " + data.id + ":" + " 删除的name: " + data.name); } }); } $(function () { // 显示文本 xx = $('#maincontainer').multiSelect({ items: [ {id: 'k001', name: '这是文本一'}, {id: 'k002', name: '这是文本二', selected: true}, {id: 'k003', name: '这是文本三'}, {id: 'k004', name: '这1文本四'}, {id: 'k005', name: '这1文本五'} ], selecteds: [ 'k003' ], maxShowCount: 4, complete: function (event, data) { $.each(data, function (i, val) { alert(val.id + ":" + val.name); }) }, del: function (event, data) { $.each(data, function (i, val) { alert("删除的ID: " + val.id + ":" + " 删除的name: " + val.name); }) } }); }); </script> </body> </html>
实现的 js 方法封装部分:
/** * Created by ZhangML on 2019/3/5. */ (function ($) { //它带有两个参数:一个是要创建的插件名称,一个是包含支持插件的函数的对象文字。 $.widget("hzjd.multiSelect", { // 默认参数 options: { componentId: 'K' + parseInt(Math.random() * 100000000, 10), items: [], //所有选项, 格式 [{"id":"0","name":"xx","selected":false},...] excludes: [], //排除数组. 格式 ['id0','id1','id2',...] selecteds: [],//已选中数组. 格式 ['id0','id1','id2',...] style: 0, //0:表示下拉框, 1:表示文本框 showType: 1, //显示文本方式, 0:表示显示id,1:表示显示文本 maxShowCount: 0, //选中的文本框中最大显示个数, 0:表示全部 当style为0时有效 maxShowFormat: "已选择{0}项,共{1}项", //超过最大显示个数的显示格式 itemCountFormat: "共:{0}项", //显示全部项目数显示格式 filterCountFormat: "符合条件:{0}项", //显示符合查询条件项目数显示格式 selectedCountFormat: "已选:{0}项", //已选项目数显示格式 title: '选择条件',//窗口标题 completed: null, deleted: null, filtered: null }, _tempItems: [], _tempMap: null, _init: function () { // 创建控件,控件生命周期内会运行多次 this._initComponent(); this._initItems(); this._show(); this._showText(); }, _create: function () { // 初始化,控件生命周期内只运行一次 //alert("create"); var self = this; $(self.element).append('<div id="' + this.options.componentId + '" class="jd_widget_box"/>'); }, _initComponent: function () { var self = this; var component = $('#' + this.options.componentId); var cmpHtml = ""; if (this.options.style == 0) { cmpHtml += '<input class="result_input" type="text"/>'; } else { cmpHtml += '<div class="result_box"></div>'; } cmpHtml += '<input type="button" class="btn_add" value="+"/>'; cmpHtml += '<div class="jd_pop_box" style="display:none;">' + '<div class="jd_pop_bg"></div>' + '<div class="jd_show_box">' + '<div class="jd_top_bar">' + self.options.title + '<a class="btn_close"></a></div>' + '<div class="filter_box"><input class="filter_input" type="text"/><button class="btn_submit">确定</button></div>' + '<div class="btn_tools"><a class="btn_selected_all"><b class="icon_select_all"></b>全选</a><span class="item_count count_text"></span></div>' + '<div class="btn_tools"><a class="btn_unselected_all"><b class="icon_unselect_all"></b>全不选</a><span class="selected_count count_text"></span></div>' + '<div class="box_items">' + '<ul class="filter_list"></ul><ul class="selected_list"></ul>' + '</div></div></div>'; component.html(cmpHtml); this._bindBtnAdd(); this._bindSelectAll(); this._bindUnselectAll(); this._bindSubmit(); this._bindClose(); this._bindFilterInput(); }, selected: function () { var selectedAry = []; var allItems = this._tempItems; if (allItems != undefined && allItems != null) { for (var i = 0; i < allItems.length; i++) { var item = allItems[i]; if (item.selected) { selectedAry.push(item); } } } return selectedAry; }, removeSelected: function (id) { var item = this._tempMap.get(id); if (item != undefined && item != null) { item.selected = false; this.options.items = this._tempItems; this._trigger('deleted', null, item); } }, items: function () { return this.options.items; }, _initTempItems: function () { //初始化临时选项数组 var self = this; this._tempItems = []; var items = this.options.items; var selecteds = this.options.selecteds; var excludes = this.options.excludes; this._tempMap = new Map(); //id为key, item为value var exMap = new Map(); //id为key, id为value for (var i = 0; i < excludes.length; i++) { exMap.set(excludes[i], excludes[i]); } if (items != undefined && items != null) { //遍历全部项目,添加Option 如果项目已选中,则隐藏 for (var i = 0; i < items.length; i++) { var exItem = exMap.get(items[i].id); if (exItem != undefined && exItem != null) { continue; } var item = {}; item["id"] = items[i].id; item["name"] = items[i].name; item["selected"] = items[i].selected; item["index"] = i; //选项加上序号 this._tempItems.push(item); this._tempMap.set(item.id, item); } } if (selecteds != undefined && selecteds != null) { $.each(selecteds, function (index, id) { //遍历二维数组 var idItem = self._tempMap.get(id); if (idItem != undefined && selecteds != null) { idItem.selected = true; } }); } }, //渲染列表页面 _initItems: function () { this._initTempItems(); var leftHtml = ""; var rightHtml = ""; if (this._tempItems != undefined && this._tempItems != null) { //遍历全部项目,添加Option $.each(this._tempItems, function (index, item) { //遍历二维数组 leftHtml += "<li class='" + "item_" + index + "' itemId='" + item.id + "' itemIndex='" + index + "' itemName='" + item.name + "'>" + item.name + "<b class='icon_select_list'></b></li>"; rightHtml += "<li class='" + " selected_" + index + "' itemId='" + item.id + "' itemIndex='" + index + "' itemName='" + item.name + "'>" + item.name + "<b class='icon_unselect_list'></b></li>"; }); } $('#' + this.options.componentId + ' .filter_list').html(leftHtml); $('#' + this.options.componentId + ' .selected_list').html(rightHtml); this._bindItemClick(); this._bindSelectedClick(); }, _refresh: function (isFilter) { var scount = 0; var ncount = 0; var self = this; if (this._tempItems != undefined && this._tempItems != null) { //遍历全部项目,添加Option 如果项目已选中,则隐藏 $.each(this._tempItems, function (index, item) { //遍历二维数组 //显示或隐藏 if (item.hidden || item.selected) { $('#' + self.options.componentId + ' .filter_list .item_' + index).addClass("displayNone"); } else { ncount++; $('#' + self.options.componentId + ' .filter_list .item_' + index).removeClass("displayNone"); } if (item.selected) { scount++; $('#' + self.options.componentId + ' .selected_list .selected_' + index).removeClass("displayNone"); } else { $('#' + self.options.componentId + ' .selected_list .selected_' + index).addClass("displayNone"); } }); } var selectedCountText = this.options.selectedCountFormat.replace('{0}', scount); var itemCountText = this.options.itemCountFormat.replace('{0}', ncount); if (isFilter) { itemCountText = this.options.filterCountFormat.replace('{0}', ncount); } $('#' + this.options.componentId + ' .item_count').html(itemCountText); $('#' + this.options.componentId + ' .selected_count').html(selectedCountText); }, _show: function () { $('#' + this.options.componentId + ' .filter_input').val(""); //过滤条件清空 //显示内容 this._initTempItems(); this._refresh(); }, _filter: function (text) { //根据项目显示相应内容 //项目添加过滤属性 hidden: true 表示因过滤不显示 if (this._tempItems != undefined && this._tempItems != null) { //遍历全部项目,添加Option 如果项目已选中,则隐藏 $.each(this._tempItems, function (index, item) { //遍历二维数组 if (item.name.indexOf(text) >= 0) { item["hidden"] = false; } else { item["hidden"] = true; } }); text != "" ? this._refresh(true) : this._refresh(false); this._trigger('filtered', null, text); } }, _bindFilterInput: function () { //选中点击事件 var self = this; $('#' + this.options.componentId + ' .filter_input').on('input', function () { self._filter($(this).val()); }); }, _bindItemClick: function () { //选中点击事件 var self = this; $('#' + this.options.componentId + ' .icon_select_list').on('click', function () { var index = $(this).parent('li').attr("itemIndex"); var item = self._tempItems[index]; item["selected"] = true; self._refresh(); }); }, _bindSelectedClick: function () { //取消点击事件 var self = this; $('#' + this.options.componentId + ' .icon_unselect_list').on('click', function () { var index = $(this).parent('li').attr("itemIndex"); var item = self._tempItems[index]; item["selected"] = false; self._refresh(); }); }, _selectAll: function () { $.each(this._tempItems, function (index, item) { //遍历二维数组 if (item.hidden != true) { item.selected = true; } }); this._refresh(); }, _unselectAll: function () { $.each(this._tempItems, function (index, item) { //遍历二维数组 if (item.selected == true) { item.selected = false; } }); this._refresh(); }, _bindSelectAll: function () { //全选点击事件 var self = this; $('#' + this.options.componentId + ' .icon_select_all').on('click', function () { self._selectAll(); }); }, _bindBtnAdd: function () { //添加点击事件 var self = this; $('#' + this.options.componentId + ' .btn_add').on('click', function () { $('#' + self.options.componentId + ' .jd_pop_box').css({'display': 'block'}); }); }, _bindUnselectAll: function () { //全不选点击事件 var self = this; $('#' + this.options.componentId + ' .icon_unselect_all').on('click', function () { self._unselectAll(); }); }, _bindSubmit: function () { //确定点击事件 var self = this; $('#' + this.options.componentId + ' .btn_submit').on('click', function () { $('#' + self.options.componentId + ' .jd_pop_box').css({'display': 'none'}); self.options.items = self._tempItems; self._trigger('completed', null, self.selected()); }); }, _bindClose: function () { //取消点击事件 var self = this; $('#' + this.options.componentId + ' .btn_close').on('click', function () { self._show(); $('#' + self.options.componentId + ' .jd_pop_box').css({'display': 'none'}); }); } , _setOptions: function (options) { var key; for (key in options) { this._setOption(key, options[key]); } return this; } , _setOption: function (key, value) { // 设置参数 if (key === "items") { this.options[key] = value; return; } // In jQuery UI 1.9及以后用法 this._super(key, value); // In jQuery UI 1.8及以前用法 // $.Widget.prototype._setOption.apply(this, arguments); } , _showText: function () { var selectedItems = this.selected(); if (this.options.style == 0) { var val = ""; if (this.options.maxShowCount != 0 && selectedItems.length > this.options.maxShowCount) { var totalCount = this._tempItems.length; val = this.options.maxShowFormat.replace('{0}', selectedItems.length.toString()).replace('{1}', totalCount.toString()); } else { for (var i = 0; i < selectedItems.length; i++) { var text = selectedItems[i].name; if (this.options.showType == 0) { text = selectedItems[i].id; } if (i == 0) { val = text; } else { val += "," + text; } } } $('#' + this.options.componentId + ' .result_input').val(val); } else { var valHtml = ""; for (var i = 0; i < selectedItems.length; i++) { var text = selectedItems[i].name; if (this.options.showType == 0) { text = selectedItems[i].id; } valHtml += '<div class="item_card" itemId="' + selectedItems[i].id + '">' + text + '<b class="btn_small_del" title="点击删除"></b></div>'; } $('#' + this.options.componentId + ' .result_box').html(valHtml); this._bindBtnDelete(); } }, _bindBtnDelete: function () { var self = this; $('#' + this.options.componentId + ' .btn_small_del').on('click', function () { var itemId = $(this).parent('.item_card').attr("itemId"); self.removeSelected(itemId); }); }, _trigger: function (type, event, data) { if (type == 'completed') { this._showText(); } else if (type == 'deleted') { this._show(); this._showText(); } var callback = this.options[type]; if (callback != undefined && callback != null) { callback(event, data); } }, destroy: function () { // 释放控件 $(this.element).html(""); // In jQuery UI 1.8及以前用法 $.Widget.prototype.destroy.call(this); // In jQuery UI 1.9及以后 } }); })(jQuery);