feat(advance-table): header height auto compute

This commit is contained in:
JiwenBai 2019-10-25 19:28:04 +08:00
parent f3885202cf
commit 2191dd695c
11 changed files with 158 additions and 116 deletions

View File

@ -3,7 +3,7 @@
* @Company: Tusimple
* @Date: 2019-10-23 15:59:41
* @LastEditors: Jiwen.bai
* @LastEditTime: 2019-10-23 16:34:30
* @LastEditTime: 2019-10-25 18:58:58
-->
# Senior Usage
@ -18,6 +18,7 @@
:search="search"
:pagination="{total:data.length,limit:10,custom:true}"
@on-change="onChange"
max-width="420px"
>
<div slot="table-operation-batch-left">
<n-button size="small" @click="clear">

View File

@ -1,13 +0,0 @@
/*
* @Author: Volankey@gmail.com
* @Company: Tusimple
* @Date: 2019-10-24 14:26:24
* @LastEditors: Jiwen.bai
* @LastEditTime: 2019-10-24 14:36:59
*/
import { Store, install, storeMixin } from './store'
export default {
Store,
install,
storeMixin
}

View File

@ -1,63 +0,0 @@
/*
* @Author: Volankey@gmail.com
* @Company: Tusimple
* @Date: 2019-10-24 14:26:37
* @LastEditors: Jiwen.bai
* @LastEditTime: 2019-10-24 14:50:03
*/
let Vue = null
export class Store {
constructor (options = {}) {
const store = this
store._vm = new Vue({
data: {
$$state: {
currentHoverRow: null
}
}
})
}
get state () {
return this._vm._data.$$state
}
commit (type, payload) {
Vue.set(this._vm._data.$$state, type, payload)
}
}
export function install (_Vue) {
if (Vue && _Vue === Vue) {
if (process.env.NODE_ENV !== 'production') {
console.error(
'[vuex] already installed. Vue.use(Vuex) should be called only once.'
)
}
return
}
Vue = _Vue
// applyMixin(Vue)
}
// function applyMixin (Vue) {
// const version = Number(Vue.version.split('.')[0])
// if (version >= 2) {
// Vue.mixin({ beforeCreate: vuexInit })
// }
// /**
// * Vuex init hook, injected into each instances init hooks list.
// */
// function vuexInit () {
// const options = this.$options
// // store injection
// if (options.store) {
// this.$store =
// typeof options.store === 'function' ? options.store() : options.store
// }
// // else if (options.parent && options.parent.$store) {
// // this.$store = options.parent.$store
// // }
// }
// }

View File

@ -3,7 +3,7 @@
* @Company: Tusimple
* @Date: 2019-10-23 16:06:59
* @LastEditors: Jiwen.bai
* @LastEditTime: 2019-10-24 15:55:27
* @LastEditTime: 2019-10-25 16:28:53
-->
<template>
<!-- table body -->
@ -18,7 +18,7 @@
v-for="(column, i) in columns"
:key="i"
:style="computeCustomWidthStl(column)"
/>
>
</colgroup>
<n-tbody v-show="!loading">
<n-tr
@ -29,6 +29,8 @@
? rowClassName(rowData, i)
: rowClassName
"
@mouseenter.native="e => onRowHover(e, rowData, i)"
@mouseleave.native="e => onRowLeave(e, rowData, i)"
>
<template v-for="column in columns">
<n-td
@ -78,11 +80,14 @@
<script>
import row from '../row/index.js'
import { addClass, removeClass } from '../utils'
import { storageMixin } from '../store'
export default {
components: {
row
},
mixins: [storageMixin],
props: {
tableStl: {
type: Object,
@ -120,6 +125,21 @@ export default {
data () {
return {}
},
watch: {
'$store.state.currentHoverRow' (index, oldIndex) {
const hoverClassName = 'n-table__tr--hover'
const rowsDom = this.$el.querySelectorAll('table tr')
const oldRowDom = rowsDom[oldIndex]
const newRowDom = rowsDom[index]
console.log('TCL: newRowDom', newRowDom)
if (oldRowDom) {
removeClass(oldRowDom, hoverClassName)
}
if (newRowDom) {
addClass(newRowDom, hoverClassName)
}
}
},
mounted () {
if (this.headerRefName) {
let headerRef = this.$parent.$refs[this.headerRefName]
@ -127,6 +147,13 @@ export default {
}
},
methods: {
onRowHover (e, rowData, index) {
console.log('TCL: onRowHover -> e, rowData, index', e, rowData, index)
this.$store.commit('currentHoverRow', index)
},
onRowLeave (e, rowData) {
this.$store.commit('currentHoverRow', null)
},
computeCustomWidthStl (column) {
if (column.width) {
let width = column.width

View File

@ -3,7 +3,7 @@
* @Company: Tusimple
* @Date: 2019-10-24 15:16:41
* @LastEditors: Jiwen.bai
* @LastEditTime: 2019-10-24 15:17:28
* @LastEditTime: 2019-10-25 19:24:21
-->
<template>
<n-table
@ -17,9 +17,9 @@
v-for="(column, i) in columns"
:key="i"
:style="computeCustomWidthStl(column)"
>
/>
<col v-if="scrollBarWidth" :width="scrollBarWidth" >
<col v-if="scrollBarWidth" :width="scrollBarWidth" />
</colgroup>
<n-thead>
<n-tr>
@ -99,6 +99,10 @@ export default {
PopFilter
},
props: {
height: {
type: Number,
default: null
},
colGroupStl: {
type: Object,
default: () => ({})
@ -152,11 +156,19 @@ export default {
this.$emit('on-checkbox-all-change', v)
},
computeAlign (column) {
let stl = {}
if (column.align) {
return {
Object.assign(stl, {
'text-align': column.align
}
})
}
let height = this.height
console.log('TCL: computeAlign -> this.height', this.height)
if (height !== null) {
stl.height = `${height}px`
}
return stl
},
sortInput (value, column, sorter) {
const sortIndexs = {}

View File

@ -1,6 +1,15 @@
/*
* @Author: Volankey@gmail.com
* @Company: Tusimple
* @Date: 2019-10-25 10:13:50
* @LastEditors: Jiwen.bai
* @LastEditTime: 2019-10-25 11:24:13
*/
import Scaffold from './src/main.vue'
Scaffold.install = function (Vue) {
Scaffold.install = function(Vue) {
Scaffold.Vue = Vue
Vue.component(Scaffold.name, Scaffold)
}

View File

@ -3,7 +3,7 @@
* @Company: Tusimple
* @Date: 2019-10-23 15:57:17
* @LastEditors: Jiwen.bai
* @LastEditTime: 2019-10-24 15:31:26
* @LastEditTime: 2019-10-25 19:23:59
-->
<template>
<div
@ -35,13 +35,17 @@
<slot name="table-operation-search-right" />
</div>
</div>
<div ref="tbodyWrapper" class="n-advance-table__tbody">
<div
ref="tbodyWrapper"
class="n-advance-table__tbody"
:style="tableWrapperStl"
>
<div class="n-advance-table__fixed--left n-advance-table__fixed">
<table-header
ref="fixedLeftHeader"
:height="headerHeight"
:columns="fixedLeftColumn"
:col-group-stl="colGroup"
:scroll-bar-width="scrollBarWidth"
:sort-indexs="sortIndexs"
:selected-filter="selectedFilter"
:showing-data="showingData"
@ -93,6 +97,9 @@
v-if="pagination !== false && showingData.length"
class="n-advance-table__pagination"
>
<button @click="add">
{{ $store.state.currentHoverRow }}
</button>
<n-pagination v-model="currentPage" :page-count="pageCount" />
</div>
</div>
@ -105,17 +112,18 @@ import withapp from '../../../mixins/withapp'
import themeable from '../../../mixins/themeable'
import TableHeader from '../header/header'
import TableBody from '../body/body'
import store, { storeMixin } from '../store'
import { Store, storageMixin } from '../store'
export default {
store () {
return new Store()
},
name: 'NAdvanceTable',
store,
components: {
TableBody,
searchInput,
TableHeader
},
mixins: [storeMixin, withapp, themeable],
mixins: [storageMixin, withapp, themeable],
props: {
search: {
/**
@ -189,6 +197,7 @@ export default {
},
data () {
return {
headerHeight: 0,
copyData: [],
sortIndexs: {},
wrapperWidth: 'unset',
@ -205,6 +214,16 @@ export default {
}
},
computed: {
tableWrapperStl () {
let stl = {}
if (this.maxWidth) {
stl.maxWidth =
typeof this.maxWidth === 'number'
? this.maxWidth + 'px'
: this.maxWidth
}
return stl
},
fixedLeftColumn () {
return this.columns
.filter(column => {
@ -297,12 +316,6 @@ export default {
? this.maxHeight + 'px'
: this.maxHeight
}
if (this.maxWidth) {
stl.maxWidth =
typeof this.maxWidth === 'number'
? this.maxWidth + 'px'
: this.maxWidth
}
if (this.minHeight !== 'unset') {
stl.minHeight =
typeof this.minHeight === 'number'
@ -374,6 +387,9 @@ export default {
}
},
watch: {
'$store.state.currentHoverRow' (index, oldIndex) {
console.log('TCL: index, oldIndex', index, oldIndex)
},
currentPage (val) {
if (this.pagination.custom === true) {
this.useRemoteChange()
@ -450,11 +466,11 @@ export default {
this.tbodyWidth = this.relTable.offsetWidth
this.headerRealEl = this.$refs.header.$el.querySelector('thead')
this.headerHeight = this.headerRealEl.offsetHeight
this.fixedLeftTBodyEl = this.$refs.fixedLeftTbody.$el
// console.log(this.wrapperWidth, this.tbodyWidth)
this.init()
this.$store.commit('currentHoverRow', 1)
// window.addEventListener('resize', this.init)
},
@ -462,6 +478,12 @@ export default {
// window.removeEventListener('resize', this.init)
},
methods: {
add () {
this.$store.commit(
'currentHoverRow',
this.$store.state.currentHoverRow + 1
)
},
onBodyScrolll (event) {
this.headerRealEl.style.transform = `translate3d(-${event.target.scrollLeft}px,0,0)`
if (this.fixedLeftTBodyEl) {

View File

@ -1,22 +1,45 @@
/*
* @Author: Volankey@gmail.com
* @Company: Tusimple
* @Date: 2019-10-24 14:03:55
* @Date: 2019-10-25 11:31:12
* @LastEditors: Jiwen.bai
* @LastEditTime: 2019-10-24 14:49:04
* @LastEditTime: 2019-10-25 11:33:00
*/
import Vue from 'vue'
import Vuex from './TableStore'
Vue.use(Vuex)
export default new Vuex.Store()
export const storeMixin = {
beforeCreate: function vuexInit () {
const options = this.$options
// store injection
if (options.store) {
this.$store =
typeof options.store === 'function' ? options.store() : options.store
}
let Vue = null
export class Store {
constructor (options = {}) {
const store = this
store._vm = new Vue({
data: {
$$state: {
currentHoverRow: 1
}
}
})
}
get state () {
return this._vm._data.$$state
}
commit (type, payload) {
Vue.set(this._vm._data.$$state, type, payload)
// this.state[type] = payload
}
}
function vuexInit () {
const options = this.$options
const _Vue = options.Vue
if (_Vue) {
Vue = _Vue
}
// store injection
if (options.store) {
this.$store =
typeof options.store === 'function' ? options.store() : options.store
} else if (options.parent && options.parent.$store) {
this.$store = options.parent.$store
}
}
export const storageMixin = {
beforeCreate: vuexInit
}

View File

@ -0,0 +1,14 @@
/*
* @Author: Volankey@gmail.com
* @Company: Tusimple
* @Date: 2019-10-24 18:07:27
* @LastEditors: Jiwen.bai
* @LastEditTime: 2019-10-24 18:07:27
*/
export const removeClass = (dom, className) => {
dom.classList.remove(className)
}
export const addClass = (dom, className) => {
dom.classList.add(className)
}

View File

@ -98,6 +98,9 @@
word-wrap: break-word;
word-break: break-all;
table-layout: fixed;
tbody tr:hover {
background-color: transparent;
}
}
&::-webkit-scrollbar {
width: 5px;
@ -130,6 +133,9 @@
border-radius: 2.5px;
background: $--table-scrollbar-color;
}
tr.n-table__tr--hover {
background-color: $--table-row-hover;
}
}
@include e(header) {
overflow: hidden;
@ -137,6 +143,9 @@
i {
color: $--table-header-icon-color;
}
th {
box-sizing: border-box;
}
}
}
}

View File

@ -1,5 +1,5 @@
@import "./mixins/mixins.scss";
@import "./themes/vars.scss";
@import './mixins/mixins.scss';
@import './themes/vars.scss';
@include themes-mixin {
@include b(table) {
@ -34,6 +34,7 @@
background-color: $--table-body-background-color;
color: $--table-body-color;
tr {
transition: background-color 0.3s;
td {
padding: 16px 6px 12px 19px;
text-align: left;