UNPKG

shu-c-view

Version:

rollup 打包vue@2.7组件库框架

784 lines (782 loc) 25.3 kB
/** * @desc Select 下拉 grid 选择器 */ import _assign from 'lodash/assign'; import _includes from 'lodash/includes'; import _toNumber from 'lodash/toNumber'; import _has from 'lodash/has'; import _find from 'lodash/find'; import _get from 'lodash/get'; import _isNil from 'lodash/isNil'; import _isEmpty from 'lodash/isEmpty'; import _isString from 'lodash/isString'; import _isArray from 'lodash/isArray'; import _difference from 'lodash/difference'; import _isEqual from 'lodash/isEqual'; import _findIndex from 'lodash/findIndex'; import { devConsole } from '../helper/util.js'; const BaseSelectGrid = { name: 'BaseSelectGrid', inheritAttrs: false, model: { prop: 'selectGridValue', event: 'selectGridChange' }, props: { // 最多只能选择几个数量 maxItem: { type: Number, default: 20 }, // 输入框宽度 width: { type: [Number, String], default: 160 }, // grid 面板宽度 gridWidth: { type: Number, default: 490 }, // 传入默认选中值 ['',''] 需要默认选中时请结合 'defaultCheckedRows' 参数 // 值的匹配必须和 'defaultCheckedRows'相同 selectGridValue: { type: [String, Array], default() { return []; } }, // 默认要勾选 grid 的节点 keys 必须是唯一值 id 的 value // [{name: '', id: ''}] name 和 id 对应 displayField 和 valueField defaultCheckedRows: { type: Array, default() { return []; } }, // 搜索栏字段,如:searchField="name" searchField: { type: String }, // Select 组件头部内容 prefixLabel: { type: String }, // 是否多选 multiple: { type: Boolean, default: false }, // 显示字段 displayField: { type: String, default: 'name' }, // 真实值 valueField: { type: String, default: 'id' }, // 外部事件扩展 只有 'change' 选中值发生改变事件 listeners: { type: Object, default() { return {}; } }, // 自定义样式名 ctCls: { type: Object }, // 是否显示 isDisplay: { type: Boolean, default: true }, // 是否渲染 isRender: { type: Boolean, default: true }, // 单选情况时点击行是否隐藏面板 idSingleSelectedHide: { type: Boolean, default: true } }, watch: { selectGridValue(val, oldVal) { if (!_isNil(val) && val.length === 0) { this.clear(); } else { if (_isArray(val) && this.multiple && !_isEqual(val, oldVal)) { if (val.length < oldVal.length) { const aDifferenceList = _difference(oldVal, val); // 删除哪几个值 this.outValueRemove(aDifferenceList); } else { const aDifferenceList = _difference(val, oldVal); // 添加哪几个值 this.outValueAdd(aDifferenceList); } } // 单选 this.setSingleNode(); } } }, data() { this.currentPageTable = []; return { gridUserRef: `${this._uid}-selectGrid`, elSelectRef: `${this._uid}-base-select-grid-ref`, popoverVisible: false, // 本地数据 curSelectRowList: [], curSelectLabelList: [], curSelectValueList: [], // 复选 curSelectRow: null, curSelectLabel: '', // 单选 curSelectValue: '', // curDefaultCheckedRows: [...this.defaultCheckedRows], gridValue: [], options: [], // [{ value: '', label: '' }] searchInput: '' }; }, methods: { /** * @desc 获取 grid 对象 */ getGrid() { return this.$refs[this.gridUserRef]; }, /** * @desc 手动打开 grid 下拉面板 */ handOpenGrid() { setTimeout(() => { this.popoverVisible = true; }, 0); }, /** * @desc 创建 el-popover */ createPopover() { const vNode = []; const h = this.$createElement; vNode.push( h( 'el-popover', { ref: `${this._uid}-base-select-grid-popover`, props: { popperClass: 'base-select-grid-el-popover', placement: 'bottom-start', // title: '标题', width: this.gridWidth, trigger: 'click', value: this.popoverVisible // content: 'hello' }, on: { input: val => { this.popoverVisible = val; } } }, [ this.createGrid(), h( 'div', { slot: 'reference', style: { height: '0px' }, ref: 'bbb' }, // 'click 激活' [] ) ] ) ); return vNode; }, /** * @desc 创建 el-select 节点 */ createSelect() { const h = this.$createElement; let prefixLabelVNode = h(); // Select 组件头部内容 if (this.prefixLabel) { prefixLabelVNode = h( 'span', { style: { lineHeight: '32px' }, slot: 'prefix' }, this.prefixLabel ); } const vNode = h( 'el-select', { ref: this.elSelectRef, style: { width: _isString(this.width) ? this.width : `${this.width}px` // 文本框控件宽度 }, attrs: { id: this.$attrs.id, autofocus: this.$attrs.autofocus, placeholder: this.$attrs.placeholder }, props: _assign( {}, { value: this.multiple ? this.curSelectValueList : this.curSelectValue, clearable: true, // 有清除按钮 multiple: this.multiple, // 设置多选,value对应为数组 'collapse-tags': true // 合并多选 }, this.$attrs ), on: { 'hook:mounted': () => { this.selectInputHeight = this.$refs[ this.elSelectRef ].$el.offsetHeight; // input 框的高度 }, clear: () => { this.clear(); this.$emit('selectGridChange', this.multiple ? [] : ''); this.change([]); this.$emit('clear', this.multiple ? [] : ''); this.setSelectPanel2InputOffsetTop(); }, 'remove-tag': tag => { const index = _findIndex( this.curSelectValueList, value => value === tag ); const optionIndex = _findIndex( this.options, item => item[this.valueField] === tag ); if (index !== -1) { this.curSelectRowList.splice(index, 1); this.curSelectLabelList.splice(index, 1); this.curSelectValueList.splice(index, 1); } if (optionIndex !== -1) { this.options.splice(optionIndex, 1); } this.$emit('selectGridChange', this.curSelectValueList); this.change(this.curSelectRowList); this.$emit('remove-tag', tag); this.setSelectPanel2InputOffsetTop(); this.$refs[this.gridUserRef].selectRows([ { field: this.valueField, value: tag } ]); } }, nativeOn: { click: event => { if ( !_has(this.$attrs, 'disabled') || (_has(this.$attrs, 'disabled') && this.$attrs.disabled === false) ) { this.$refs[this.elSelectRef].blur(); this.$refs.bbb.click(); // 如果是 el-button ,那么自动触发 click 事件 `this.$refs.bbb.$el.click();` event.stopPropagation(); event.preventDefault(); return false; } } } }, [ prefixLabelVNode, this.createOptions(), h( 'div', { class: 'base-select-grid-down-empty', slot: 'empty', style: { display: 'none' } }, [] ) ] ); return vNode; }, /** * @desc 创建下拉 grid 控件 */ createGrid() { const h = this.$createElement; let searchNode = h(); if (!_isNil(this.searchField) && !_has(this.$slots, 'search')) { searchNode = this.createSearchBar(); } if (_has(this.$slots, 'search')) { searchNode = this.$slots.search; } return h( 'base-grid', { class: 'base-grid-panel-content-cls', ref: this.gridUserRef, attrs: {}, props: _assign( { api: this.$attrs.api, // 初始化查询参数 queryParams: this.$attrs.queryParams || this.$attrs['query-params'], columns: this.$attrs.columns, selectMode: this.multiple, isReloadGrid: true, isSelectedFirstRow: false, loadFilter: this.$attrs.loadFilter || this.$attrs['load-filter'], tableAttributes: { size: 'mini', border: true }, paginationAttributes: { layout: 'prev, pager, next, slot, ->, total', pageSize: 10, pageSizes: [5, 10, 15, 20] } }, this.$attrs ), on: { 'row-click': (row, column, event) => { // 单选,没有复选框 if (!this.multiple) { this.curSelectLabel = row[this.displayField]; this.curSelectValue = row[this.valueField]; this.curSelectRow = row; this.options = [ { [this.displayField]: row[this.displayField], [this.valueField]: row[this.valueField] } ]; this.$emit('selectGridChange', row[this.valueField]); } if (this.idSingleSelectedHide) { this.popoverVisible = false; // 隐藏 Popover 弹出框 } event.stopPropagation(); // js 阻止事件冒泡 }, select: (selection, row) => { // 当用户手动勾选数据行的 Checkbox 时触发的事件 const values = _assign([], this.selectGridValue); const displayLabels = _assign([], this.curSelectLabelList); for (let i = 0, length = selection.length; i < length; i++) { if (!_includes(values, selection[i][this.valueField])) { values.push(selection[i][this.valueField]); displayLabels.push(selection[i][this.displayField]); } } if (_includes(this.selectGridValue, row[this.valueField])) { // 取消选中 const index = this.selectGridValue.findIndex( val => val === row[this.valueField] ); if (index !== -1) { values.splice(index, 1); displayLabels.splice(index, 1); } } const selectRow = _find(this.curSelectRowList, o => { return _get(o, this.valueField) === row[this.valueField]; }); if (_isNil(selectRow)) { this.curSelectRowList.push(row); } this.curSelectLabelList = displayLabels; this.curSelectValueList = values; const option = _find(this.options, o => { return _get(o, this.valueField) === row[this.valueField]; }); if (_isNil(option)) { this.options.push({ [this.displayField]: row[this.displayField], [this.valueField]: row[this.valueField] }); } this.$emit('selectGridChange', values); this.setSelectPanel2InputOffsetTop(); }, 'select-all': selection => { // 当用户手动勾选全选 Checkbox 时触发的事件 // const values = []; const values = _assign([], this.curSelectValueList); const displayLabels = _assign([], this.curSelectLabelList); const data = _isEmpty(selection) ? this.currentPageTable : selection; for (let i = 0, length = data.length; i < length; i++) { if (_isEmpty(selection)) { const rowSelectIndex = _findIndex( values, item => item === _get(data[i], this.valueField) ); console.log('rowSelectIndex ', rowSelectIndex); if (rowSelectIndex !== -1) { values.splice(rowSelectIndex, 1); displayLabels.splice(rowSelectIndex, 1); this.options.splice(rowSelectIndex, 1); } } else if (!_includes(values, data[i][this.valueField])) { values.push(data[i][this.valueField]); displayLabels.push(data[i][this.displayField]); const option = _find(this.options, o => { return ( _get(o, this.valueField) === data[i][this.valueField] ); }); const selectRow = _find(this.curSelectRowList, o => { return ( _get(o, this.valueField) === data[i][this.valueField] ); }); if (_isNil(option)) { this.options.push({ [this.displayField]: selection[i][this.displayField], [this.valueField]: selection[i][this.valueField] }); } if (_isNil(selectRow)) { this.curSelectRowList.push(selection[i]); } } } this.curSelectLabelList = displayLabels; this.curSelectValueList = values; this.$emit('selectGridChange', values); this.setSelectPanel2InputOffsetTop(); }, onLoadSuccess: this.afterDataLoadHandler } }, [h('template', { slot: 'search' }, [searchNode])] ); }, /** * @desc 创建搜索栏 */ createSearchBar() { const h = this.$createElement; const VNode = this.$createElement( 'div', { class: 'base-select-grid__search-box' }, [ h( 'el-input', { attrs: { placeholder: '请输入内容', maxlength: '40' }, props: { value: this.searchInput, 'show-word-limit': true, clearable: true }, on: { input: val => { this.searchInput = val; } } }, [] ), h( 'el-button', { props: { type: 'primary' }, on: { click: () => { let params = { [this.searchField]: '' }; if (this.searchInput.length > 0) { params = { [this.searchField]: this.searchInput }; } this.getGrid().setQueryParams(params); this.getGrid().reloadGrid(); } } }, ['搜索'] ) ] ); return VNode; }, /** * @desc 创建 el-option 节点 */ createOptions() { const h = this.$createElement; const vNode = this.options.map(option => { return h('el-option', { style: { /* width: `${this.gridWidth}px`, height: 'auto', 'max-height': `${this.gridHeight}px`, 'background-color': this.backgroundColor, padding: '0px', overflow: 'auto', */ display: 'absolute', top: '0px', left: '0px', height: '0px', 'z-index': '-100' // display: 'none' }, props: { key: option[this.valueField], label: option[this.displayField], value: option[this.valueField] }, on: { 'hook:mounted': () => {} } }); }); return vNode; }, /** * @desc 设置单选-选中效果 */ setSingleNode() { // 设置单选-选中效果 }, afterDataLoadHandler(data) { // 翻页时如果当前页有要选中的行那么设置选中效果 this.currentPageTable = data; setTimeout(() => { const selectRows = []; const b = defaultCheckedRow => { if (_isEmpty(this.options)) { this.options.push({ [this.displayField]: _get(defaultCheckedRow, this.displayField), [this.valueField]: _get(defaultCheckedRow, this.valueField) }); } else { const option = _find(this.options, o => { return ( _get(o, this.valueField) === _get(defaultCheckedRow, this.valueField) ); }); if (_isNil(option)) { this.options.push({ [this.displayField]: _get(defaultCheckedRow, this.displayField), [this.valueField]: _get(defaultCheckedRow, this.valueField) }); } } }; // 单选 if (!_isArray(this.selectGridValue)) { const defaultCheckedRow = _find( data, o => _get(o, this.valueField) === this.selectGridValue ); this.curSelectLabel = _get(defaultCheckedRow, this.displayField); this.curSelectValue = this.selectGridValue; if (!_isNil(defaultCheckedRow)) { b(defaultCheckedRow); } return; } for (let i = 0, length = this.selectGridValue.length; i < length; i++) { selectRows.push({ field: this.valueField, value: this.selectGridValue[i] }); const aRows = data; let defaultCheckedRow = _find( aRows, o => _get(o, this.valueField) === this.selectGridValue[i] ); if (_isNil(defaultCheckedRow) && !_isEmpty(this.defaultCheckedRows)) { defaultCheckedRow = _find( this.defaultCheckedRows, o => _get(o, this.valueField) === this.selectGridValue[i] ); } if (this.multiple) { if ( _isNil( _find( this.curSelectValueList, o => o === this.selectGridValue[i] ) ) ) { this.curSelectValueList.push(this.selectGridValue[i]); this.curSelectLabelList.push( _get(defaultCheckedRow, this.displayField, '') ); this.curSelectRowList.push(defaultCheckedRow); } } else { // 单选 this.curSelectLabel = _get(defaultCheckedRow, this.displayField); this.curSelectValue = this.selectGridValue[i]; } if (!_isNil(defaultCheckedRow)) { b(defaultCheckedRow); } } this.$refs[this.gridUserRef].selectRows(selectRows); }, 0); }, /** * @desc 计算下拉面板和 input 框之间的高度差值 */ setSelectPanel2InputOffsetTop() { setTimeout(() => { const popoverEl = this.$refs[`${this._uid}-base-select-grid-popover`] .$el; if (!_isNil(popoverEl) && !_isNil(popoverEl.childNodes)) { const selectInputHeight = this.$refs[this.elSelectRef].$el .clientHeight; // input 框的高度 const oldTopNum = this.$refs[ this.gridUserRef ].$el.parentNode.style.top.replace('px', ''); if (selectInputHeight > this.selectInputHeight) { const dValue = selectInputHeight - this.selectInputHeight; // 差值 this.$refs[ this.gridUserRef ].$el.parentNode.style.top = `${_toNumber(oldTopNum) + _toNumber(dValue)}px`; } else if (selectInputHeight <= this.selectInputHeight) { const dValue = this.selectInputHeight - selectInputHeight; if (dValue !== 0) { this.$refs[ this.gridUserRef ].$el.parentNode.style.top = `${_toNumber(oldTopNum) - _toNumber(dValue)}px`; } } this.selectInputHeight = selectInputHeight; } }, 100); }, /** * @desc 清空 */ clear() { if (this.multiple) { // 取消选中的行 for (let i = 0, len = this.curSelectValueList.length; i < len; i++) { this.$refs[this.gridUserRef].selectRows([ { field: this.valueField, value: this.curSelectValueList[i] } ]); } } else { // 单选-取消选中的行 this.$refs[this.gridUserRef].selectRow(this.curSelectRow); } this.curSelectRowList = []; this.curSelectLabelList = []; this.curSelectValueList = []; this.curSelectRow = null; this.curSelectLabel = ''; this.curSelectValue = ''; // this.curDefaultCheckedRows = []; this.gridValue = []; this.options = []; }, /** * @desc 自定义change事件 * @param {Array|String} val */ change(val) { 'change' in this.listeners && this.listeners.change(val); }, /** * @desc 外部 v-model 直接操作值 */ outValueRemove(aDifferenceList) { const rows = this.getGrid().getData(); const tableEl = this.getGrid().getElTable(); for (let i = 0, len = aDifferenceList.length; i < len; i++) { const aDifferenceVal = aDifferenceList[i]; const index = _findIndex( this.curSelectValueList, v => v === aDifferenceVal ); if (index !== -1) { const row = _find( rows, v => _get(v, this.valueField, '') === aDifferenceVal ); tableEl.toggleRowSelection(row, false); // 取消选中 this.curSelectRowList.splice(index, 1); this.curSelectLabelList.splice(index, 1); this.curSelectValueList.splice(index, 1); this.options.splice(index, 1); } } }, /** * @desc 外部 v-model 直接操作值 */ outValueAdd(aDifferenceList) { const rows = this.getGrid().getData(); const tableEl = this.getGrid().getElTable(); for (let i = 0, len = aDifferenceList.length; i < len; i++) { const aDifferenceVal = aDifferenceList[i]; const index = _findIndex( this.curSelectValueList, v => v === aDifferenceVal ); if (index === -1) { let row = _find( rows, v => _get(v, this.valueField, '') === aDifferenceVal ); if (_isNil(row) && !_isEmpty(this.defaultCheckedRows)) { row = _find( this.defaultCheckedRows, v => _get(v, this.valueField, '') === aDifferenceVal ); } tableEl.toggleRowSelection(row, true); // 取消选中 this.curSelectRowList.push(row); this.curSelectLabelList.push(_get(row, this.displayField)); this.curSelectValueList.push(_get(row, this.valueField)); this.options.push({ [this.displayField]: _get(row, this.displayField), [this.valueField]: _get(row, this.valueField) }); } } } }, render(h) { return h( 'div', { ref: `${this._uid}-base-grid-panel`, style: { width: _isString(this.width) ? this.width : `${this.width}px` }, class: { 'base-select-grid': true, [this.ctCls]: this.ctCls } }, [this.createSelect(), this.createPopover()] ); } }; BaseSelectGrid.install = function(Vue, ElComponents) { // 用于按需加载的时候独立使用 devConsole(`按需加载独立组件:${BaseSelectGrid.name}`); if (_isArray(ElComponents) && !_isEmpty(ElComponents)) { for (let i = 0; i < ElComponents.length; i++) { if (ElComponents[i].name !== BaseSelectGrid.name) { Vue.use(ElComponents[i]); } } } Vue.component(BaseSelectGrid.name, BaseSelectGrid); }; export { BaseSelectGrid };