UNPKG

kui-vue

Version:

A high quality UI Toolkit built on Vue.js 2.0

350 lines (336 loc) 10.8 kB
import { hasChild, sortHeaderCols, findItem, } from './utils' import { measureScrollBar } from '../_tool/utils' import { Checkbox } from '../checkbox' import Icon from '../icon' import { CaretUp, CaretDown } from 'kui-icons' export default { name: 'ExtendTable', props: { body: Array, columns: Array, columns2: Array, height: [Number, String], width: Number, hasExpand: Boolean, indeterminate: Boolean, sticky: [Boolean, Number], checkAll: Boolean, }, data() { return { scrollBarHeight: 0, // type: 'left', theadSync: false, tbodySync: false } }, mounted() { let { thead } = this.$refs if (thead && !this.$isServer) { // thead.style.marginBottom = `-${thead.offsetHeight - thead.scrollHeight}px` let size = measureScrollBar() this.scrollBarHeight = size if (this.height && this.width) { this.setColWidth() } } }, methods: { setColWidth() { const cols = this.$refs.colgroup.children//[0].children // reset tbody's height let col = this.columns2 || this.columns for (let i = 0; i < cols.length; i++) { if (col[i] && !col[i].width) { col[i].width = cols[i].getBoundingClientRect().width } } }, sorter(item) { let { _order, sorter } = item if (sorter) { if (!_order) { _order = 'asc' } else if (_order == 'desc') { _order = null } else { _order = 'desc' } if (hasChild(this.columns)) { //有子集的话,原来的数据结构被重新排序了,所以要判断当前的item 是原始数据的item再传回 item = findItem(item, this.columns) } this.$set(item, '_order', _order) this.$emit('sorter', item) } }, renderCol(hasHead) { const isFixedHeader = this.height !== undefined let cols = [] let columns = this.columns2 || this.columns columns.forEach((col, i) => { let width = col.width || ''//(isFixedHeader ? 150 : '') let hasCheckbox = col.type == 'selection' // if (isFixedHeader && i == columns.length - 2 && columns.length > 2) width = '' // set Cols let colProps = { style: { width: `${width}px` }, class: [{ 'k-table-selection-col': hasCheckbox, // 'k-table-cell-fixed-left': col.fixed == 'left', // 'k-table-cell-fixed-right': col.fixed == 'right', }] } if (!width) { delete colProps.style.width } if (col.fixed == 'right') { // colProps.style = { width: `${width || 100}px`} } cols.push(<col {...colProps} />) }) if (this.hasExpand) { cols.unshift(<col class="k-table-expand-icon-col"></col>) } if (isFixedHeader && hasHead) { cols.push(<col style={{ width: this.scrollBarHeight + 'px' }}></col>) } return <colgroup ref="colgroup">{cols}</colgroup> }, renderSort(col) { return (col.sorter) ? (<span class="k-table-sorter"> <Icon type={CaretUp} class={{ actived: col._order == 'asc' }} /> <Icon type={CaretDown} class={{ actived: col._order == 'desc' }} /> </span>) : null }, renderTH(col, left, right) { let hasCheckbox = col.type == 'selection' const hasSort = col.sorter let props = { class: { 'k-table-cell-ellipsis': col.ellipsis, 'k-table-cell-selection': hasCheckbox, 'k-table-cell-fixed-left': col.fixed == 'left', 'k-table-cell-fixed-right': col.fixed == 'right', 'k-table-cell-fixed-left-last': col.last, 'k-table-cell-fixed-right-first': col.first, 'k-table-cell-sorter': hasSort, [col.className]: col.className }, attrs: { key: col.key, colSpan: col.colSpan > 1 ? col.colSpan : null, rowSpan: col.rowSpan }, on: {}, style: {} } if (col.fixed == 'left') { props.style.left = left + 'px' } if (col.fixed == 'right') { props.style.right = right + 'px' } if (hasSort) { props.on.click = () => this.sorter(col) } // if (hasCheckbox) { // console.log(this.checkAll, this.indeterminate) // } let inner = hasCheckbox && col.checkType !== 'radio' ? <Checkbox indeterminate={this.indeterminate} checked={this.checkAll} onChange={this.onSelectAll} /> : (col.$title || col.title) return ( <th {...props}> <span class="k-table-header-col"> {inner ? <span class="k-table-header-title">{inner}</span> : null} {hasSort ? this.renderSort(col) : null} </span> </th> ) }, renderHead() { let cols = [] if (hasChild(this.columns)) { cols = sortHeaderCols(this.columns) } else { cols = this.columns } if (!cols || cols.length == 0) return null; let head = [], ths = [], hasFR = false, left = 0, right = cols.filter(c => c.fixed == 'right').map(c => c.width).reduce((a, b) => a + b, 0) + (this.height ? this.scrollBarHeight : 0) cols.forEach((col, i) => { if (Array.isArray(col)) { let ths = [], r = col.filter(c => c.fixed == 'right').map(c => c.width).reduce((a, b) => a + b, 0) + (this.height ? this.scrollBarHeight : 0) col.forEach((co, j) => { if (co.fixed == 'left' && j > 0) { left += col[j - 1].width } if (co.fixed == 'right' && i < col.length) { r -= co.width } let th = this.renderTH(co, left, r) ths.push(th) }) if (i == 0 && this.width) { ths.push(<th rowSpan={col.length} class="k-table-cell-fixed-right" style={{ width: this.scrollBarHeight + 'px' }}></th>) } head.push(<tr>{ths}</tr>) } else { // set Head hasFR = col.fixed == 'right' if (col.colSpan !== 0) { if (col.fixed == 'left' && i > 0) { left += cols[i - 1].width } if (col.fixed == 'right' && i < cols.length) { right -= col.width } let th = this.renderTH(col, left, right) ths.push(th) } } }) if (this.hasExpand) { ths.unshift(<th></th>) } if (this.height != undefined) { let cls = [] let hasFR = cols.filter(c => c.fixed == 'right') if (hasFR) { cls.push('k-table-cell-fixed-right') } ths.push(<th style={{ width: this.scrollBarHeight + 'px' }} class={cls}></th>) } if (!head.length) { head.push(<tr>{ths}</tr>) } let props = { style: {} } if (!this.height && this.sticky) { props.class = 'k-table-thead-sticky' if (this.sticky > 0) { props.style.top = this.sticky + 'px' } } return <thead ref="head" {...props}>{head}</thead> }, renderTable(hasHead, body) { let props = {} props.style = { width: `${this.width}px` } return ( <table {...props}> {this.renderCol(hasHead)} {hasHead ? this.renderHead(hasHead) : null} {body ? <tbody ref="tbody">{body}</tbody> : null} </table> ) }, onSelectAll(e) { this.$emit('select-all', e) }, asyncScroll(e, target) { let min = 0, max = e.target.scrollWidth - e.target.offsetWidth, scrollLeft = e.target.scrollLeft; scrollLeft = Math.round(scrollLeft); if (target) { if (target == 'tbody') { if (!this.theadSync) { this.theadSync = true this.$refs[target].scrollLeft = scrollLeft } this.theadSync = false } if (target == 'thead') { if (!this.tbodySync) { this.tbodySync = true this.$refs[target].scrollLeft = scrollLeft } this.tbodySync = false } } let ping = 'left' // console.log(min, scrollLeft, max) if (scrollLeft > min && scrollLeft < max) { ping = 'middle' } else if (scrollLeft == min) { ping = 'left' } else if (scrollLeft == max || scrollLeft - this.scrollBarHeight == max) { ping = 'right' } this.$emit('ping', ping) // this.$refs.table.setAttribute('class', `k-table11-ping-${ping}`) } }, render() { let { height, width, body, scrollBarHeight, sticky } = this let rootProps = { // ref: 'table', class: [`k-table-container`, // // { [`k-table-ping-${type}`]: width != undefined }, ], style: { height: body && body.length ? '100%' : 'auto' }, on: {} } let has_sticky = sticky !== undefined && sticky > 0 if (width && !height && !has_sticky) { rootProps.style.overflow = 'auto'; rootProps.on.scroll = e => this.asyncScroll(e) //只有左右,没有header scroll } const content = [] if (height || (width && has_sticky)) { let headProps = { class: [`k-table-thead`, { 'k-table-thead-sticky': has_sticky }], on: { scroll: e => this.asyncScroll(e, 'tbody') }, ref: 'thead', style: { // marginBottom: -scrollBarHeight + 'px' } } if (has_sticky) { headProps.style.top = sticky + 'px' } // if (width && height && !has_sticky) { // headProps.style.marginBottom = -scrollBarHeight + 'px' // } // if (has_sticky) { headProps.style.overflow = 'hidden' // } else if (height) { // headProps.style.overflow = 'auto' // } if (this.columns && this.columns.length) { content.push(<div {...headProps}>{this.renderTable(true, false)}</div>) } const props = { class: `k-table-body`, style: { }, on: { scroll: e => this.asyncScroll(e, 'thead') }, ref: "tbody" } if (height) { props.style = { height: height + (typeof height === 'number' ? 'px' : ''), overflow: 'auto scroll' } } else if (width || has_sticky) { props.style = { overflow: 'auto hidden' } } if (body && body.length) { content.push(<div {...props}>{this.renderTable(false, body)}</div>) } } else { content.push(this.renderTable(true, body)) } return ( <div {...rootProps}>{content}</div > ) } }