ivue-material-plus
Version:
A high quality UI components Library with Vue.js
345 lines (314 loc) • 8.14 kB
text/typescript
import {
h,
defineComponent,
inject,
getCurrentInstance,
onMounted,
nextTick,
ref,
} from 'vue';
import IvueIcon from '../../ivue-icon/index.vue';
import useUtils from './utils';
import useStyle from './styles';
import useEvent from './events';
import useTableLayoutObserver from '../table-layout-observer';
// 过滤组件
import FilterPanel from '../table/filter-panel.vue';
// ts
import { TableContextKey } from '../table/defaults';
import type { TableColumnCtx } from '../table-column/defaults';
import type { PropType } from 'vue';
import type {
TableHeader,
FilterPanelInstance,
TableHeaderProps,
} from './types';
const prefixCls = 'ivue-table';
export default defineComponent({
props: {
/**
* 列是否固定在左侧或者右侧。 true 表示固定在左侧
*
* @type {String}
*/
fixed: {
type: String,
default: '',
},
/**
* store
*
* @type {Object}
*/
store: {
required: true,
type: Object as PropType<TableHeaderProps['store']>,
},
/**
* 是否带有纵向边框
*
* @type {Boolean}
*/
border: {
type: Boolean,
default: false,
},
/**
* 默认的排序列的 prop 和顺序。
*
* @type {Object}
*/
defaultSort: {
type: Object as PropType<TableHeaderProps['defaultSort']>,
default: () => {
return {
prop: '',
order: '',
};
},
},
/**
* tooltip点击是否阻止当前事件在捕获和冒泡阶段的进一步传播
*
* @type {Boolean}
*/
tooltipStop: {
type: Boolean,
},
},
setup(props: TableHeaderProps, { emit }) {
// vm
const vm = getCurrentInstance() as TableHeader;
// inject
const IvueTable = inject(TableContextKey);
// data
// 过滤的列节点
const filterPanels = ref<Record<number, FilterPanelInstance>>({});
const {
// 获取当前列的行数
columnRows,
isGroup,
} = useUtils(props);
const {
// 头部行样式
getHeaderCellClass,
getHeaderCellStyle,
getHeaderRowStyle,
getHeaderRowClass,
} = useStyle(props);
// 事件
const {
handleSortClick,
handleHeaderClick,
handleMouseDown,
handleMouseMove,
handleMouseOut,
} = useEvent(props, emit);
// 布局改变监听
const { handleColumnsChange, handleScrollableWidthChange } =
useTableLayoutObserver(IvueTable);
vm.state = {
handleColumnsChange,
handleScrollableWidthChange,
};
vm.filterPanels = filterPanels;
// methods
// 渲染排序
const renderSortable = (column) => {
// 是否有排序
if (!column.sortable) {
return null;
}
return h(
'span',
{
class: `${prefixCls}-header--sortable`,
},
[
// 上按钮
h(
IvueIcon,
{
class: `${prefixCls}-header--ascending`,
onClick: ($event: Event) => {
handleSortClick($event, column, 'ascending');
},
},
{
default: () => 'arrow_drop_up',
}
),
// 下按钮
h(
IvueIcon,
{
class: `${prefixCls}-header--descending`,
onClick: ($event: Event) => {
handleSortClick($event, column, 'descending');
},
},
{
default: () => 'arrow_drop_down',
}
),
]
);
};
// 渲染头部
const renderHeader = (column, cellIndex: number) => {
// 是否有头部
if (!column.renderHeader) {
return column.label;
}
return h('span', {}, [
column.renderHeader({
column,
$index: cellIndex,
store: props.store,
_self: vm.$parent,
}),
]);
};
// 渲染过滤
const renderFilter = (column: TableColumnCtx) => {
if (!column.filterable) {
return null;
}
return h(FilterPanel, {
// 当前列
column,
// store
store: props.store,
// 过滤弹出框的定位
placement: column.filterPlacement,
// tooltip点击是否阻止当前事件在捕获和冒泡阶段的进一步传播
tooltipStop: props.tooltipStop,
// 更新列数据
upDataColumn: (key: string, value: boolean) => {
column[key] = value;
},
});
};
// 渲染 th
const renderTh = (
list: TableColumnCtx[],
rowSpan: number,
rowIndex: number
) => {
return list.map((column: TableColumnCtx, cellIndex: number) => {
// 规定单元格可横跨的行数
if (column.rowSpan > rowSpan) {
rowSpan = column.rowSpan;
}
return h(
'th',
{
// class
class: getHeaderCellClass(rowIndex, cellIndex, list, column),
// style
style: getHeaderCellStyle(rowIndex, cellIndex, list, column),
// 规定单元格可横跨的列数。
colspan: column.colSpan,
// 规定单元格可横跨的行数
rowspan: column.rowSpan,
// key
key: `${column.id}-thead`,
onClick: ($event: Event) => {
// 头部点击
handleHeaderClick($event, column);
},
// 鼠标按下
onMousedown: ($event: MouseEvent) => {
handleMouseDown($event, column);
},
// 鼠标移动
onMousemove: ($event: MouseEvent) => {
handleMouseMove($event, column);
},
// 鼠标退出
onMouseout: () => {
handleMouseOut();
},
},
[
// cell
h(
'div',
{
class: [
'cell',
// 是否有选择过滤
column.filteredValue && column.filteredValue.length > 0
? 'highlight'
: '',
],
},
h(
'div',
{
class: 'cell-content',
},
[
// 渲染头部
renderHeader(column, cellIndex),
// 排序
renderSortable(column),
// 渲染过滤
renderFilter(column),
]
)
),
]
);
});
};
// onMounted
onMounted(() => {
nextTick(() => {
const { prop, order } = props.defaultSort;
IvueTable?.store.commit('sort', { prop, order, init: true });
});
});
return {
// data
filterPanels,
// computed
isGroup,
columnRows,
// methods
renderTh,
handleColumnsChange,
getHeaderRowStyle,
getHeaderRowClass,
};
},
render() {
const {
columnRows,
renderTh,
isGroup,
getHeaderRowStyle,
getHeaderRowClass,
} = this;
const rowSpan = 1;
return h(
'thead',
{
class: {
['is-group']: isGroup,
},
},
columnRows.map((item: TableColumnCtx, rowIndex: number) => {
return h(
'tr',
{
class: getHeaderRowClass(rowIndex),
style: getHeaderRowStyle(rowIndex),
key: rowIndex,
},
renderTh(item, rowSpan, rowIndex)
);
})
);
},
});