element-plus
Version:
A Component Library for Vue3.0
170 lines (163 loc) • 4.89 kB
text/typescript
import {
getCurrentInstance,
h,
ComputedRef,
ref,
computed,
watchEffect,
} from 'vue'
import { cellForced, defaultRenderCell, treeCellPrefix } from '../config'
import { parseWidth, parseMinWidth } from '../util'
import { TableColumnCtx, TableColumn } from './defaults'
function useRender<T>(
props: TableColumnCtx<T>,
slots,
owner: ComputedRef<any>,
) {
const instance = getCurrentInstance() as TableColumn<T>
const columnId = ref('')
const isSubColumn = ref(false)
const realAlign = ref<string>()
const realHeaderAlign = ref<string>()
watchEffect(() => {
realAlign.value = !!props.align ? 'is-' + props.align : null
// nextline help render
realAlign.value
})
watchEffect(() => {
realHeaderAlign.value = !!props.headerAlign
? 'is-' + props.headerAlign
: realAlign.value
// nextline help render
realHeaderAlign.value
})
const columnOrTableParent = computed(() => {
let parent: any = instance.vnode.vParent || instance.parent
while (parent && !parent.tableId && !parent.columnId) {
parent = parent.vnode.vParent || parent.parent
}
return parent
})
const realWidth = ref(parseWidth(props.width))
const realMinWidth = ref(parseMinWidth(props.minWidth))
const setColumnWidth = (column: TableColumnCtx<T>) => {
if (realWidth.value) column.width = realWidth.value
if (realMinWidth.value) {
column.minWidth = realMinWidth.value
}
if (!column.minWidth) {
column.minWidth = 80
}
column.realWidth = Number(
column.width === undefined ? column.minWidth : column.width,
)
return column
}
const setColumnForcedProps = (column: TableColumnCtx<T>) => {
// 对于特定类型的 column,某些属性不允许设置
const type = column.type
const source = cellForced[type] || {}
Object.keys(source).forEach(prop => {
const value = source[prop]
if (value !== undefined) {
column[prop] = prop === 'className' ? `${column[prop]} ${value}` : value
}
})
return column
}
const checkSubColumn = (children: TableColumn<T> | TableColumn<T>[]) => {
if (children instanceof Array) {
children.forEach(child => check(child))
} else {
check(children)
}
function check(item: TableColumn<T>) {
if (item?.type?.name === 'ElTableColumn') {
item.vParent = instance
}
}
}
const setColumnRenders = (column: TableColumnCtx<T>) => {
// renderHeader 属性不推荐使用。
if (props.renderHeader) {
console.warn(
'[Element Warn][TableColumn]Comparing to render-header, scoped-slot header is easier to use. We recommend users to use scoped-slot header.',
)
} else if (column.type !== 'selection') {
column.renderHeader = scope => {
// help render
instance.columnConfig.value['label']
const renderHeader = slots.header
return renderHeader ? renderHeader(scope) : column.label
}
}
let originRenderCell = column.renderCell
// TODO: 这里的实现调整
if (column.type === 'expand') {
// 对于展开行,renderCell 不允许配置的。在上一步中已经设置过,这里需要简单封装一下。
column.renderCell = data =>
h(
'div',
{
class: 'cell',
},
[originRenderCell(data)],
)
owner.value.renderExpanded = data => {
return slots.default ? slots.default(data) : slots.default
}
} else {
originRenderCell = originRenderCell || defaultRenderCell
// 对 renderCell 进行包装
column.renderCell = data => {
let children = null
if (slots.default) {
children = slots.default(data)
} else {
children = originRenderCell(data)
}
const prefix = treeCellPrefix(data)
const props = {
class: 'cell',
style: {},
}
if (column.showOverflowTooltip) {
props.class += ' el-tooltip'
props.style = {
width:
(data.column.realWidth || Number(data.column.width)) - 1 + 'px',
}
}
checkSubColumn(children)
return h('div', props, [prefix, children])
}
}
return column
}
const getPropsData = (...propsKey: unknown[]) => {
return propsKey.reduce((prev, cur) => {
if (Array.isArray(cur)) {
cur.forEach(key => {
prev[key] = props[key]
})
}
return prev
}, {})
}
const getColumnElIndex = (children, child) => {
return [].indexOf.call(children, child)
}
return {
columnId,
realAlign,
isSubColumn,
realHeaderAlign,
columnOrTableParent,
setColumnWidth,
setColumnForcedProps,
setColumnRenders,
getPropsData,
getColumnElIndex,
}
}
export default useRender