mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2025-01-18 12:34:25 +08:00
feat(advance-table): header height auto compute
This commit is contained in:
parent
f3885202cf
commit
2191dd695c
@ -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">
|
||||
|
@ -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
|
||||
}
|
@ -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
|
||||
// // }
|
||||
// }
|
||||
// }
|
@ -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
|
||||
|
@ -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 = {}
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
export default new Vuex.Store()
|
||||
export const storeMixin = {
|
||||
beforeCreate: function vuexInit () {
|
||||
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
|
||||
}
|
||||
|
14
packages/common/AdvanceTable/utils.js
Normal file
14
packages/common/AdvanceTable/utils.js
Normal 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)
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user