shu-c-view
Version:
rollup 打包vue@2.7组件库框架
784 lines (782 loc) • 25.3 kB
JavaScript
/**
* @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 };