| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418 |
- js SelectRenderer封装类
- /**
- * Select渲染器
- */
- class SelectRenderer {
- constructor(config = {}) {
- this.config = $.extend({
- placeholder: true,
- placeholderText: '请选择',
- allowClear: false,
- searchable: false,
- ajax: false,
- data: [],
- valueField: 'value',
- textField: 'text',
- disabledField: 'disabled',
- selectedField: 'selected',
- groupField: 'group'
- }, config);
- }
- /**
- * 渲染单个select
- * @param {jQuery|string} selector - 选择器或jQuery对象
- * @param {Array|Object} data - 数据
- * @param {Object} options - 选项
- */
- render(selector, data = null, options = {}) {
- var $select = $(selector);
- if (!$select.length) return;
- var config = $.extend({}, this.config, options);
- var renderData = data || config.data;
- // 清空现有选项
- $select.empty();
- // 添加占位符
- if (config.placeholder) {
- var $placeholder = $('<option>', {
- value: '',
- text: config.placeholderText
- });
- if (config.allowClear) {
- $placeholder.attr('data-allow-clear', 'true');
- }
- $select.append($placeholder);
- }
- // 渲染选项
- if ($.isArray(renderData)) {
- this._renderOptions($select, renderData, config);
- } else if (renderData && renderData.url) {
- this._renderWithAjax($select, renderData, config);
- }
- // 触发渲染完成事件
- $select.trigger('select:rendered');
- return $select;
- }
- /**
- * 渲染多个select
- * @param {string} className - 类选择器
- * @param {Array} data - 数据
- * @param {Object} options - 选项
- */
- renderAll(className, data = null, options = {}) {
- var self = this;
- var results = [];
- $(className).each(function() {
- var $select = $(this);
- var specificOptions = $.extend({}, options);
- // 从data-*属性读取配置
- var dataAttrs = self._getDataAttributes($select);
- $.extend(specificOptions, dataAttrs);
- results.push(self.render($select, data, specificOptions));
- });
- return results;
- }
- /**
- * 内部方法:渲染选项
- */
- _renderOptions($select, data, config) {
- var groups = {};
- $.each(data, function(index, item) {
- // 分组处理
- if (config.groupField && item[config.groupField]) {
- var groupName = item[config.groupField];
- if (!groups[groupName]) {
- groups[groupName] = [];
- }
- groups[groupName].push(item);
- } else {
- var $option = $('<option>', {
- value: item[config.valueField] || item.value || '',
- text: item[config.textField] || item.text || '',
- disabled: item[config.disabledField] || item.disabled || false,
- selected: item[config.selectedField] || item.selected || false
- });
- // 添加自定义属性
- $.each(item, function(key, value) {
- if (!['value', 'text', 'disabled', 'selected'].includes(key)) {
- $option.attr('data-' + key, value);
- }
- });
- $select.append($option);
- }
- });
- // 渲染分组
- this._renderOptionGroups($select, groups, config);
- }
- /**
- * 内部方法:渲染分组
- */
- _renderOptionGroups($select, groups, config) {
- $.each(groups, function(groupName, items) {
- var $optgroup = $('<optgroup>', {
- label: groupName
- });
- $.each(items, function(index, item) {
- var $option = $('<option>', {
- value: item[config.valueField] || item.value || '',
- text: item[config.textField] || item.text || '',
- disabled: item[config.disabledField] || item.disabled || false,
- selected: item[config.selectedField] || item.selected || false
- });
- $optgroup.append($option);
- });
- $select.append($optgroup);
- });
- }
- /**
- * 内部方法:通过AJAX渲染
- */
- _renderWithAjax($select, ajaxConfig, config) {
- var self = this;
- // 显示加载状态
- $select.prop('disabled', true).addClass('loading');
- $.ajax($.extend({
- type: 'GET',
- dataType: 'json',
- success: function(response) {
- // 处理响应数据
- var data = response;
- if (ajaxConfig.dataProcessor && typeof ajaxConfig.dataProcessor === 'function') {
- data = ajaxConfig.dataProcessor(response);
- } else if (response.data) {
- data = response.data;
- }
- // 渲染数据
- self._renderOptions($select, data, config);
- // 恢复select状态
- $select.prop('disabled', false).removeClass('loading');
- // 触发完成事件
- $select.trigger('select:ajax:complete', [response]);
- },
- error: function(xhr, status, error) {
- console.error('加载下拉框数据失败:', error);
- // 添加错误选项
- $select.empty();
- $select.append($('<option>', {
- value: '',
- text: '数据加载失败',
- disabled: true
- }));
- // 恢复状态
- $select.prop('disabled', false).removeClass('loading');
- // 触发错误事件
- $select.trigger('select:ajax:error', [xhr, status, error]);
- }
- }, ajaxConfig));
- }
- /**
- * 获取data-*属性
- */
- _getDataAttributes($element) {
- var attrs = {};
- var data = $element.data();
- // 转换属性名
- $.each(data, function(key, value) {
- if (key.startsWith('select')) {
- var newKey = key.replace(/^select/, '');
- newKey = newKey.charAt(0).toLowerCase() + newKey.slice(1);
- attrs[newKey] = value;
- }
- });
- return attrs;
- }
- /**
- * 设置选中值
- */
- setValue($select, value) {
- $select.val(value).trigger('change');
- return this;
- }
- /**
- * 启用/禁用
- */
- setDisabled($select, disabled) {
- $select.prop('disabled', disabled);
- return this;
- }
- /**
- * 重新加载数据
- */
- reload($select) {
- var dataAttrs = this._getDataAttributes($select);
- if (dataAttrs.url) {
- this._renderWithAjax($select, { url: dataAttrs.url }, dataAttrs);
- }
- return this;
- }
- }
- 使用示例
- HTML结构
- <!-- 基础select -->
- <select class="form-select" id="category1"></select>
- <!-- 带配置的select -->
- <select class="form-select"
- data-select-url="/api/categories"
- data-select-value-field="id"
- data-select-text-field="name"
- data-select-placeholder="选择分类">
- </select>
- <!-- 多个相同配置的select -->
- <select class="department-select" data-department-id="1"></select>
- <select class="department-select" data-department-id="2"></select>
- <select class="department-select" data-department-id="3"></select>
- JavaScript使用
- $(function() {
- // 创建渲染器实例
- var selectRenderer = new SelectRenderer({
- placeholderText: '请选择',
- valueField: 'id',
- textField: 'name'
- });
- // 示例1:渲染静态数据
- var staticData = [
- {id: '1', name: '技术部'},
- {id: '2', name: '市场部', disabled: true},
- {id: '3', name: '人事部'},
- {id: '4', name: '财务部'}
- ];
- selectRenderer.render('#category1', staticData);
- // 示例2:通过AJAX渲染单个select
- selectRenderer.render('.form-select[data-select-url]', {
- url: '/api/departments',
- dataProcessor: function(response) {
- // 处理返回数据
- return response.list || response.data || [];
- }
- });
- // 示例3:批量渲染相同class的select
- $('.department-select').each(function() {
- var departmentId = $(this).data('department-id');
- var url = '/api/employees?deptId=' + departmentId;
- selectRenderer.render(this, {
- url: url,
- placeholderText: '选择员工'
- });
- });
- // 示例4:使用事件监听
- $('.form-select').on('select:rendered', function() {
- console.log('Select已渲染:', $(this).attr('id'));
- }).on('change', function() {
- console.log('选择的值:', $(this).val());
- });
- });
- 扩展:集成Select2(如果需要增强功能)
- /**
- * 集成Select2的渲染器
- */
- class Select2Renderer extends SelectRenderer {
- constructor(config = {}) {
- var defaultSelect2Config = {
- theme: 'bootstrap',
- width: '100%',
- allowClear: true,
- placeholder: '请选择'
- };
- super($.extend({
- select2: defaultSelect2Config
- }, config));
- }
- render(selector, data = null, options = {}) {
- var $select = super.render(selector, data, options);
- // 初始化Select2
- if (options.select2 || this.config.select2) {
- var select2Config = $.extend({}, this.config.select2, options.select2);
- // 设置placeholder
- if (options.placeholderText) {
- select2Config.placeholder = options.placeholderText;
- }
- $select.select2(select2Config);
- // 监听销毁事件,防止内存泄漏
- $(window).on('unload', function() {
- $select.select2('destroy');
- });
- }
- return $select;
- }
- setValue($select, value) {
- if ($select.data('select2')) {
- $select.val(value).trigger('change.select2');
- } else {
- super.setValue($select, value);
- }
- return this;
- }
- }
- // 使用Select2Renderer
- $(function() {
- var select2Renderer = new Select2Renderer();
- select2Renderer.render('.select2-enhanced', {
- url: '/api/data',
- select2: {
- theme: 'bootstrap4',
- ajax: {
- url: '/api/search',
- dataType: 'json',
- delay: 250,
- data: function(params) {
- return {
- q: params.term,
- page: params.page
- };
- }
- }
- }
- });
- });
- CSS样式建议
- /* 加载状态 */
- select.loading {
- background-image: url('loading-spinner.svg');
- background-repeat: no-repeat;
- background-position: right 10px center;
- background-size: 16px 16px;
- padding-right: 35px;
- }
- /* 错误状态 */
- select.error {
- border-color: #dc3545;
- background-color: #fff5f5;
- }
- /* 禁用状态 */
- select:disabled {
- background-color: #e9ecef;
- cursor: not-allowed;
- }
- /* 分组样式 */
- optgroup {
- font-weight: bold;
- font-style: normal;
- color: #495057;
- }
- optgroup option {
- font-weight: normal;
- padding-left: 20px;
- }
|