封装是为了快速开发页面,提高开发效率,封装的表格只是针对于单级表头的情况,多级表格还是使用element-ui表格好一点。话不多说上代码。
<template>
<div>
<el-table ref="list"
:border="tableBorder"
:data="table.list"
:class="tableCss"
:max-height="maxHeight ? maxHeight : ''"
v-loading="loading"
:header-row-style="tableHeadStyle"
:row-key="rowKey ? rowKey : getRowKey"
default-expand-all
@sort-change="table.sort ? table.sort.actionChange($event) : ''"
:tree-props="table.expend"
@select-all="table.selection ? selectAll : ''"
@selection-change="table.selection ? table.selection.actionChange($event) : ''"
:default-sort = "table.defaultSort"
v-horizontal-scroll="scrollOptions"
style="width: 100%">
<el-table-column v-if="table.selection" type="selection" align="center" :selectable="selectRes" width="55" reserve-selection></el-table-column>
<el-table-column v-for="(item, index) in table.head"
:key="index" :label="item.label"
:prop="item.props" :align="item.align ? item.align : 'center'"
:width="table.head.length===1 ? '' : item.width"
:min-width="item.minWidth ? item.minWidth : ''"
:sortable="item.sortable ? item.sortable : false"
:fixed="item.fixed ? item.fixed : false">
<template slot="header" slot-scope="scope">
<!--表格是否展示提示信息-->
<template v-if="item.headerTips">
<span>{{item.label}}</span>
<el-tooltip effect="dark" placement="top">
<template slot="content">
<div class="c-max-width600" v-html="item.headerTips"></div>
</template>
<svg-icon icon-class="icon_tips" class="c-fs-12 c-fc-sgray"></svg-icon>
</el-tooltip>
</template>
<template v-else>
{{item.label}}
</template>
</template>
<template slot-scope="scope">
<!--字典类型展示-->
<div v-else-if="item.columnType === 'dictionary'" :style="{color:item.dictionaryColor?item.dictionaryColor[scope.row[item.props]]:''} " >
<template v-if="(scope.row[item.props] || utilsIsNumber(scope.row[item.props])) && item.dictionary[scope.row[item.props]]">{{item.dictionary[scope.row[item.props]]}}</template>
<template v-else>--</template>
</div>
<!--可以点击列-->
<div v-else-if="item.columnType === 'underlineDictionary'" @click="item.action(scope.row, item.props)" class="c-fc-blue c-textD-u pointer">
{{ scope.row[item.props] ? (item.dictionary[scope.row[item.props]] ? item.dictionary[scope.row[item.props]] : '--') : (scope.row[item.props] === 0 ? (item.dictionary[scope.row[item.props]] ? item.dictionary[scope.row[item.props]] : '--') :'--') }}
</div>
<!--点击可以修改的列-->
<div v-else-if="item.columnType === 'numberFormat'" class="c-flex-row c-justify-center c-aligni-center">
<number-format :value="scope.row[item.props]"></number-format><span v-if="item.unit">{{item.unit}}</span>
</div>
<!--可以点击列-->
<div v-else-if="item.columnType === 'underline'" @click="item.action(scope.row, item.props)" class="c-fc-blue c-textD-u pointer">
<template v-if="scope.row[item.props] || utilsIsNumber(scope.row[item.props])">{{scope.row[item.props]}}</template>
<template v-else>--</template>
<template v-if="item.unit">{{item.unit}}</template>
</div>
<!--可以点击列-->
<div v-else-if="item.columnType === 'percentage'">
<span v-if="scope.row[item.props] || utilsIsNumber(scope.row[item.props])">
{{scope.row[item.props]}}%
</span>
<span v-else>--</span>
</div>
<!--点击可以修改的列-->
<div v-else-if="item.columnType === 'underlineNumberFormat'" @click="item.action(scope.row, item.props)" class="c-fc-blue c-textD-u pointer c-flex-row c-justify-center c-aligni-center">
<number-format :value="scope.row[item.props]"></number-format><span v-if="item.unit">{{item.unit}}</span>
</div>
<!--slot类型展示-->
<template v-else-if="item.columnType === 'slot'">
<slot :name="item.props" :data="scope.row"></slot>
</template>
<span v-else>
{{ scope.row[item.props] ? scope.row[item.props] : (scope.row[item.props] === 0 ? scope.row[item.props] :'--') }}<span v-if="item.unit">{{item.unit}}</span>
</span>
</template>
</el-table-column>
</el-table>
<el-pagination
class="c-textAlign-r c-pv20"
v-show="showPage"
background
@current-change="currentChange"
@size-change="sizeChange"
:page-sizes="[10, 20, 30, 40]"
:current-page.sync="listBase.page"
:page-size.sync="listBase.size"
:layout="layout"
:total="listBase.total"
></el-pagination>
</div>
</template>
<script>
import numberFormat from '@/views/templatePage/numberFormat'
import { directiveVue1, directiveVue2 } from '@/components/horizontalScroll.js'
export default {
name: 'index',
components: { numberFormat },
props: {
// 加载状态
loading: {
type: Boolean,
default: false
},
// 表格参数
table: {
type: Object,
default: () => { return [] }
},
// 分页参数
listBase: {
type: Object,
required: true,
default: {
page: 1,
total: 1,
size: 10
}
},
// 是否提供tableKey
rowKey: {
type: String,
default: ''
},
// 表格是否限制高度
maxHeight: {
type: Number,
default: null
},
// 是否自动获取高度
autoTableHeight: {
type: Boolean,
default: false
},
// 分页功能
layout: {
type: String,
default: 'total, prev, pager, next, jumper'
},
// 表格边框
tableBorder: {
type: Boolean,
default: false
},
/**
* 滚动条自定义参数
* closeScroll:关闭悬浮滚动条,不传默认开启悬浮滚动条
* hasBottomBox:是否有底部操作栏(默认60px高),设为true时,需传bottom: 100px
* bottom:悬浮滚动条距离页面底部距离,不传默认40px
*/
scrollOptions: {
type: Object,
default: function() {
return {}
}
}
},
watch: {
},
created() {
},
directives: {
// 自定义指令,实现悬浮横向滚动条
'horizontal-scroll': {
...directiveVue1,
...directiveVue2
}
},
computed: {
// 判断是否展示分页
showPage() {
if (this.listBase) {
return (this.listBase.total / this.listBase.size) > 0
} else {
return false
}
}
},
data() {
return {
// 表格样式
tableHeadStyle: { 'font-family': 'PingFangSC-Semibold', 'backgroundColor': '#f5f7fa', 'color': '#333333' },
tableCss: 'c-width100 c-fc-333 family-PingFangSC-Regular c-fs-12'
}
},
methods: {
// 判断是否为数字
utilsIsNumber(row) {
return Object.prototype.toString.call(row) === '[object Number]'
},
// 改变分页大小
sizeChange(row) {
this.$emit('sizeChange', row)
},
// 表格唯一指定key
getRowKey(row) {
const random = this.randomString()
return 'column' + random
},
// 获取随机字符串
randomString(len) {
len = len || 32
const chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'
const maxPos = chars.length
let pwd = ''
for (let i = 0; i < len; i++) {
pwd += chars.charAt(Math.floor(Math.random() * maxPos))
}
return pwd
},
// 选择全部
selectAll(val) {
val.map((item, index) => {
if (item.selectable === false) {
this.$refs.list.toggleRowSelection(item, false)
}
})
},
// 禁用选中, boolean 值
selectRes(row) {
return row.selectable === false ? row.selectable : true
},
// 提交分页
currentChange(val) {
this.$emit('currentChange', val)
},
// 清除选择
clearSelect() {
this.$refs.list.clearSelection()
}
}
}
</script>
<style lang="scss" scoped>
</style>
表格中设计的组件numberFormat数字格式化组件 当然你也可以不加
<template>
<div class="c-flex-row c-flexw-wrap c-justify-center c-aligni-end" :class="valueClass">
<template v-if="value || utilsIsNumber(value)">
<template v-if="Number(value)!==0">
<template v-if="Number(value) < 0">-</template>
<template v-if="!!calculate">
{{calculate}}
<div class="c-fs-12 c-ph2" :class="unitClass">亿</div>
</template>
<template v-if="!!myriad">
{{myriad}}
<div class="c-fs-12 c-ph2" :class="unitClass">万</div>
</template>
<template v-if="!!thousand">{{thousand}}</template>
<template :class="unitClass">{{unit}}</template>
</template>
<template v-else>
0
</template>
</template>
<template v-else>--</template>
</div>
</template>
<script>
import { utilsIsNumber } from '@/utils'
export default {
name: 'numberFormat',
props: {
value: {
type: [String, Number],
default: ''
},
unitClass: {
type: String,
default: ''
},
valueClass: {
type: String,
default: ''
},
unit: {
type: String,
default: ''
}
},
data() {
return {
calculate: 0,
myriad: 0,
thousand: 0
}
},
created() {
this.calculateFormatHandle()
},
watch: {
value() {
this.calculateFormatHandle()
}
},
methods: {
// 判断是否为数字
utilsIsNumber(row) {
return Object.prototype.toString.call(row) === '[object Number]'
},
// 亿格式化数字方法
calculateFormatHandle() {
const number = Math.abs(Number(this.value))
if (number >= 100000000) {
this.calculate = parseInt((number / 100000000) + '')
} else {
this.calculate = 0
}
this.myriadFormatHandle()
},
// 万格式化数字方法
myriadFormatHandle() {
const number = Math.abs(Number(this.value)) - (this.calculate * 100000000)
if (number >= 10000) {
this.myriad = parseInt((number / 10000) + '')
} else {
this.myriad = 0
}
this.thousandFormatHandle()
},
// 千格式化数字方法
thousandFormatHandle() {
const number = Math.abs(Number(this.value)) - ((this.calculate * 100000000) + (this.myriad * 10000))
if (number >= 0) {
this.thousand = Number(Number(number).toFixed(2))
} else {
this.thousand = 0
}
}
}
}
</script>
<style scoped>
</style>
表格中涉及的指令horizontalScroll.js用于优化表格滚动条 当然你也可以不加去除指令
/**
* el-table表格,横向滚动条
*/
import { throttle } from 'throttle-debounce'
const THROTTLE_TIME = 1000 / 60
class Scroller {
/**
* 给tableBody创建一个scroller
* @param {Element} targetTableWrapperEl
* @param {Element} bottomIsVisibleObserverEl
* @param {string} options 指令对象参数
*/
constructor(targetTableWrapperEl, bottomIsVisibleObserverEl, options = {}) {
if (!targetTableWrapperEl) {
throw new Error('need have table element')
}
this.targetTableWrapperEl = targetTableWrapperEl
this.fullwidth = false // 表格是否满宽,无需滚动
this.mode = options.hasOwnProperty('mode') ? options.mode : 'always' // 滚动条的显示方式
this.isVisible = false // 滚动条是否显示
this.isBlock = false // 表格数据是否为空
this.bottomIsVisibleObserverEl = bottomIsVisibleObserverEl
this.hasBottomBox = options.hasOwnProperty('hasBottomBox') ? options.hasBottomBox : false // 页面是否有底部操作栏,有则进行延迟隐藏
/**
* 创建相关dom
* scroller:横向滚动条容器
* bar:滑动槽
* thumb:滑块
*/
const scroller = document.createElement('div')
scroller.classList.add('el-scrollbar', 'el-table-horizontal-scrollbar')
scroller.style.height = '30px'
scroller.style.borderRadius = '100px'
scroller.style.background = 'rgba(255, 255, 255, 0.7)'
scroller.style.boxShadow = 'rgba(0, 0, 0, 0.15) 0px 2px 16px 0px'
scroller.style.position = 'fixed'
scroller.style.bottom = options.hasOwnProperty('bottom') ? options.bottom : '40px'
scroller.style.zIndex = 10
scroller.style.transition = 'all 0.3s ease'
this.dom = scroller
this.resetScroller()
const bar = document.createElement('div')
bar.classList.add('el-scrollbar__bar', 'is-horizontal')
bar.style.width = '95%'
bar.style.height = '10px'
bar.style.borderRadius = '10px'
bar.style.background = 'rgb(241, 241, 241)'
bar.style.left = '0px'
bar.style.margin = '8px auto'
this.bar = bar
scroller.appendChild(bar)
const thumb = document.createElement('div')
thumb.classList.add('el-scrollbar__thumb')
bar.appendChild(thumb)
this.thumb = thumb
this.bottomIsVisible = false
/**
* 初始化配置
*/
const instance = this
this.checkIsScrollBottom = throttle(THROTTLE_TIME, function() {
// 此处3个判断具有先后顺序,不能放一起判断
// 移动端进入后台,因屏幕自带滚动,不需要该滚动条(最高优先级)
if (window.innerWidth <= 768) {
instance.hideScroller()
return
}
// 如果表格数据为空,优先不显示滚动条
if (instance.isBlock) {
instance.hideScroller()
return
}
// 滚动条是否显示
if (!instance.isVisible) {
instance.hideScroller()
return
}
// 当前表格的底部是否出现在可视区域
if (instance.bottomIsVisible) {
instance.hideScroller()
instance.hideBar()
} else {
// 需要重新设置一次当前宽度
instance.resetBar(false)
// 显示当前的bar
instance.showScroller()
if (instance.mode === 'always') {
instance.showBar()
}
if (instance.mode === 'hover') {
instance.hideBar()
}
}
})
// 自动同步,table => scroller
targetTableWrapperEl.addEventListener('scroll', throttle(THROTTLE_TIME, function() {
instance.resetThumbPosition()
}))
// 自动同步 scroller => table
this.syncDestoryHandler = this.initScrollSyncHandler()
this.tableElObserver = null
if (MutationObserver) {
// 监听table的dom变化,自动重新设置
this.tableElObserver = new MutationObserver(() => {
// 如果表格没有数据,则优先设置为不显示滚动条(主表格下存在空样式元素,防止嵌套表格的空样式元素影响了主表格)
// :scope 可以用于代替当前元素的选择器,因主表格没有特殊记号表示,会导致能取到嵌套内表格的空元素,加上该选择器后就不会选到孙代元素
this.isBlock = Boolean(targetTableWrapperEl.querySelector(':scope > .el-table__empty-block'))
this.forceUpdate()
})
this.tableElObserver.observe(
targetTableWrapperEl.querySelector('.el-table__body'),
{
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['style']
}
)
}
this.tableResizeObserver = null
// 兼容一下不支持ResizeObserver的旧版浏览器
if (window.ResizeObserver) {
this.tableResizeObserver = new ResizeObserver(() => this.forceUpdate())
this.tableResizeObserver.observe(targetTableWrapperEl)
} else {
window.addEventListener('resize', throttle(THROTTLE_TIME, function() {
instance.forceUpdate()
}))
}
this.tableIntersectionObserver = null
this.bottomIsVisibleObserver = null
if (IntersectionObserver) {
// 本体是否可见
this.tableIntersectionObserver = new IntersectionObserver(([entry]) => {
this.isVisible = entry.intersectionRatio > 0
this.forceUpdate()
})
this.tableIntersectionObserver.observe(targetTableWrapperEl)
// 底部是否可见
if (this.bottomIsVisibleObserverEl) {
// 判断是否有底部操作栏,有则延迟60px再进行隐藏滚动条,防止因操作栏遮挡导致提前隐藏了滚动条
const config = this.hasBottomBox ? { rootMargin: '0px 0px -60px 0px' } : null
this.bottomIsVisibleObserver = new IntersectionObserver(([entry]) => {
// 获取监听的底部元素的相对视口数据
const elRect = this.bottomIsVisibleObserverEl.getBoundingClientRect() || { top: 0 }
// 当页面没有滚动条,表格直接在视口内时,intersectionRatio会为0,悬浮滚动条会和表格本体一起出现
// 因此这里额外判断一下,当底部元素的距视口高度,小于视口的高度时,将bottomIsVisible置为true,表示当前底部元素已在视口中
// 如果有底部操作栏,视口高度要减去延迟的60px
const inViewport = this.hasBottomBox ? elRect.top <= window.innerHeight - 60 : elRect.top <= window.innerHeight
this.bottomIsVisible = inViewport ? true : entry.intersectionRatio > 0
this.checkIsScrollBottom()
}, config)
this.bottomIsVisibleObserver.observe(this.bottomIsVisibleObserverEl)
}
}
// bar宽度自动重制
this.forceUpdate()
}
/**
* 自动设置Bar
* @param {boolean} changeScrollerVisible 是否开启自动设置滚动条显示与否
*/
resetBar(changeScrollerVisible = true) {
const { targetTableWrapperEl } = this
const widthPercentage = (targetTableWrapperEl.clientWidth * 100 / targetTableWrapperEl.scrollWidth)
const thumbWidth = Math.min(widthPercentage, 100)
this.thumb.style.width = `${thumbWidth}%`
this.fullwidth = thumbWidth >= 100
if (changeScrollerVisible) {
if (this.fullwidth) {
this.hideScroller()
} else {
this.checkIsScrollBottom()
}
}
}
// 重置滑块定位
resetThumbPosition() {
this.thumb.style.transform = `translateX(${this.moveX}%)`
}
// 重置滚动条位置
resetScroller() {
const { targetTableWrapperEl, dom } = this
const boundingClientRect = targetTableWrapperEl.getBoundingClientRect()
dom.style.width = '500px'
// 因fiexd定位是根据整个页面来的,外加侧边栏改动,部分表格不是占满页面,故更改公式,已主表格中心为准
// 表格宽度的一半,减去滚动条宽度的一半,加上表格距离页面左侧的宽度,以实现滚动条始终在表格中心
dom.style.left = `calc(${boundingClientRect.width / 2}px - 250px + ${boundingClientRect.left}px)`
}
forceUpdate() {
setTimeout(() => {
this.resetBar()
this.resetScroller()
this.resetThumbPosition()
this.checkIsScrollBottom()
}, THROTTLE_TIME)
}
// 获取横向偏移距离
get moveX() {
const { targetTableWrapperEl } = this
return ((targetTableWrapperEl.scrollLeft * 100) / targetTableWrapperEl.clientWidth)
}
/**
* 让scroller的拖动行为和table的同步
* 处理类似element-ui的拖拽处理
*/
initScrollSyncHandler() {
let cursorDown = false
let tempClientX = 0
let rate = 1
let tableRate = 1
const { thumb, targetTableWrapperEl, bar } = this
function getRate() {
// 计算一下变换比例,拖拽走的是具体数字,但是这个实际上应该是按照比例变的
return bar.offsetWidth / thumb.offsetWidth
}
function getTableRate() {
// 获取表格滚动条和悬浮滚动条之间的宽度比例
const scrollEl = targetTableWrapperEl.getBoundingClientRect()
return scrollEl.width / bar.offsetWidth
}
const mouseMoveDocumentHandler = throttle(
THROTTLE_TIME,
function(e) {
if (cursorDown === false) {
return
}
const { clientX } = e
const offset = clientX - tempClientX
const originTempClientX = tempClientX
tempClientX = clientX
const tempScrollleft = targetTableWrapperEl.scrollLeft
targetTableWrapperEl.scrollLeft += offset * rate * tableRate
if (tempScrollleft === targetTableWrapperEl.scrollLeft) {
tempClientX = originTempClientX
}
})
function mouseUpDocumentHandler() {
cursorDown = false
document.removeEventListener('mousemove', mouseMoveDocumentHandler)
document.removeEventListener('mouseup', mouseUpDocumentHandler)
document.onselectstart = null
}
/**
* 拖拽处理
* @param {MouseEvent} e
*/
function startDrag(e) {
e.stopImmediatePropagation()
cursorDown = true
document.addEventListener('mousemove', mouseMoveDocumentHandler)
document.addEventListener('mouseup', mouseUpDocumentHandler)
document.onselectstart = () => false
}
thumb.onmousedown = function(e) {
if (e.ctrlKey || e.button === 2) {
return
}
const { clientX } = e
tempClientX = clientX
rate = getRate()
tableRate = getTableRate()
startDrag(e)
}
/**
* 点击槽快速移动
* @param {PointerEvent} e
*/
bar.onclick = function(e) {
const { target } = e
if (target !== bar) {
return
}
rate = getRate()
tableRate = getTableRate()
const { clientX } = e
// 计算规则更改:鼠标点击的x轴偏移量,减去滑动槽左侧偏移量,点击位置在滑块右侧时,需额外减去滑块宽度
let offset = 0
const thumbPosition = thumb.getBoundingClientRect()
const barPosition = bar.getBoundingClientRect()
if (thumbPosition.left >= clientX) {
offset = clientX - barPosition.left
} else {
offset = clientX - barPosition.left - thumbPosition.width
}
/**
* 因 targetTableWrapperEl.scrollLeft 实际上是走的表格滚动条的 scrollLeft
* 通过x轴偏移量计算出来的结果(offset),需要乘上槽与块的宽度比(rate),再乘上表格滚动条与悬浮滚动条的宽度比(tableRate)
* 最后得出的结果就是实际上表格滚动条的 scrollLeft
* 因悬浮滚动条的槽两端,很难点到头和尾,故再乘以1.01,使之点击槽两端时能尽量滚到头和尾
*/
const targetScrollLeft = offset * rate * tableRate * 1.01
// 兼容一下没有scrollTo方法的浏览器
if (targetTableWrapperEl.scrollTo) {
targetTableWrapperEl.scrollTo({
left: targetScrollLeft,
behavior: 'smooth' // 平滑滚动
})
} else {
targetTableWrapperEl.scrollLeft = targetScrollLeft
}
}
return function() {
document.removeEventListener('mouseup', mouseUpDocumentHandler)
}
}
/**
* 显示整体
*/
showScroller() {
if (!this.fullwidth) {
this.dom.style.display = 'initial'
}
}
/**
* 隐藏整体
*/
hideScroller() {
this.dom.style.display = 'none'
}
/**
* 显示滚动条
*/
showBar() {
if (!this.isVisible) {
return
}
if (this.mode === 'hover') {
this.dom.style.opacity = 1
}
this.bar.style.opacity = 1
}
/**
* 隐藏滚动条
*/
hideBar() {
if (!this.isVisible) {
return
}
if (this.mode === 'hover') {
this.dom.style.opacity = 0
}
this.bar.style.opacity = 0
}
destory() {
// 取消所有监听事件,销毁滚动条元素
this.tableElObserver && this.tableElObserver.disconnect()
this.tableResizeObserver && this.tableResizeObserver.disconnect()
const instance = this
if (window.ResizeObserver && this.tableResizeObserver) {
this.tableResizeObserver.disconnect()
} else {
window.removeEventListener('resize', throttle(THROTTLE_TIME, function() {
instance.forceUpdate()
}))
}
this.tableIntersectionObserver && this.tableIntersectionObserver.disconnect()
this.bottomIsVisibleObserver && this.bottomIsVisibleObserver.disconnect()
if (this.bottomIsVisibleObserverEl && this.bottomIsVisibleObserverEl.parentElement) {
this.bottomIsVisibleObserverEl.parentElement.removeChild(this.bottomIsVisibleObserverEl)
}
this.syncDestoryHandler()
}
}
export const directiveVue1 = {
inserted(el, binding) {
const options = binding.value || {}
// 关闭滚动条
if (options.hasOwnProperty('closeScroll') && options.closeScroll) {
return
}
const tableBodyWrapper = el.querySelector('.el-table__body-wrapper')
const bottomIsVisibleObserverEl = document.createElement('div')
bottomIsVisibleObserverEl.style.transform = 'translateY(-12px)'
const scroller = new Scroller(tableBodyWrapper, bottomIsVisibleObserverEl, options)
el.appendChild(bottomIsVisibleObserverEl)
el.appendChild(scroller.dom)
el.horizontalScroll = scroller
if (options.hasOwnProperty('mode') && options.mode === 'hover') {
scroller.hideBar()
el.addEventListener('mouseover', scroller.showBar.bind(scroller))
el.addEventListener('mouseleave', scroller.hideBar.bind(scroller))
} else {
scroller.showBar()
}
},
unbind(el, binding) {
const options = binding.value || {}
// 已关闭的滚动条不进行销毁
if (options.hasOwnProperty('closeScroll') && options.closeScroll) {
return
}
el.horizontalScroll.destory()
}
}
export const directiveVue2 = {
mounted(el, binding) {
const options = binding.value || {}
// 关闭滚动条
if (options.hasOwnProperty('closeScroll') && options.closeScroll) {
return
}
const tableBodyWrapper = el.querySelector('.el-table__body-wrapper .el-scrollbar__wrap')
if (!tableBodyWrapper) {
return
}
const bottomIsVisibleObserverEl = document.createElement('div')
bottomIsVisibleObserverEl.style.transform = 'translateY(-12px)'
el.appendChild(bottomIsVisibleObserverEl)
const scroller = new Scroller(tableBodyWrapper, bottomIsVisibleObserverEl, options)
el.appendChild(scroller.dom)
el.horizontalScroll = scroller
if (options.hasOwnProperty('mode') && options.mode === 'hover') {
scroller.hideBar()
el.addEventListener('mouseover', scroller.showBar.bind(scroller))
el.addEventListener('mouseleave', scroller.hideBar.bind(scroller))
} else {
scroller.showBar()
}
},
unmounted(el, binding) {
const options = binding.value || {}
// 已关闭的滚动条不进行销毁
if (options.hasOwnProperty('closeScroll') && options.closeScroll) {
return
}
el.horizontalScroll && el.horizontalScroll.destory()
}
}
表格的封装已经结算了下面我们来看下要怎么去使用
<template>
<div>
<!-- 表格组件 -->
<table-list v-loading="pageLoading" ref="table" row-key="id" :table="tableArr" :list-base="listInfo" @currentChange="changePage">
</table-list>
</div>
</template>
<script>
// 导入表格
import tableList from '@/views/templatePage/tableList'
// 接口api请换成你们自己的
import { getCustomerDayAct } from '@/api/tiktok'
export default {
name: 'table',
components: { tableList },
props: {},
data() {
return {
// 表格信息
tableArr: {
// 是否自定排序(需要排序是添加)
defaultSort: { prop: 'totalMonthTalentNum', order: 'descending' },
// 选择排序(需要排序是添加)
sort: { actionChange: this.relateSort },
// 是否多选(多选时添加)
selection: { actionChange: this.selectChange },
// 表头
head: [],
// 列表
list: []
},
// 分页信息
listInfo: { page: 1, size: 10, total: 0 },
// 页面加载
pageLoading: false,
// 排序字段
searchSort: {
totalMonthTalentNumSort: 'DESC'
},
// 打款方式
payMethodMap: {
1: '微信'
},
// 多选
multipleSelection: []
}
},
created() {
this.getTableHead()
this.getCustomerDayActPort()
},
methods: {
// 分页数据
changePage(val) {
this.listInfo.page = val
this.getCustomerDayActPort()
},
// 列表选中项
selectChange(val) {
this.multipleSelection = val
},
// 获取表格头部
getTableHead() {
const tableHead = [
{ label: '运营经理', props: 'operationsManagerName', minWidth: 150, show: true },
{ label: '打款方式', props: 'payMethod', columnType: 'dictionary', dictionary: this.payMethodMap, show: true, minWidth: 100 },
{ label: '累计月交易达人数', props: 'totalMonthTalentNum', columnType: 'underline', action: this.dailyActivityDetailsHandle, sortable: 'custom', minWidth: 150, show: true }
]
this.tableArr.head = tableHead.filter(item => item.show)
},
// 排序
relateSort(row) {
this.searchSort = {}
if (row.order) {
this.searchSort[row.prop + 'Sort'] = row.order === 'descending' ? 'DESC' : 'ASC'
}
this.searchHandle()
},
// 打开详情弹出框
dailyActivityDetailsHandle() {},
// 获取搜索参数
getSearchParam() {
const searchParam = { pageNo: this.listInfo.page, pageSize: this.listInfo.size, ...this.searchSort }
const param = {}
// 排除不需要的参数
const excludeList = ['timeRange']
Object.keys(searchParam).forEach(item => {
if (!excludeList.includes(item) && (searchParam[item] || this.utilsIsNumber(searchParam[item]))) {
param[item] = searchParam[item]
}
})
return param
},
// 判断是否为数字(建议封装到utils包中)
utilsIsNumber(row) {
return Object.prototype.toString.call(row) === '[object Number]'
},
// 获取客户日活数据
async getCustomerDayActPort() {
if (this.pageLoading) return
this.pageLoading = true
const param = this.getSearchParam()
const { data: { data: result }} = await getCustomerDayAct(param).catch(() => { this.pageLoading = false })
this.pageLoading = false
if (!result) return
// 多选是是否禁止选择 selectable false-禁止选择 true-允许选择(多选是添加)
this.tableArr.list = result.records.map(item => ({ ...item, selectable: false }))
this.listInfo.total = result.total
}
}
}
</script>
<style scoped>
</style>
展示一下其他内容应用表格组件完成的效果