手把手实现自定义table组件封装
vue
<template>
<div class="table-with-label">
<!-- theader -->
<div class="table-th">
<ul class="th-title">
<li v-for="(item, index) in viewData" :key="index" :width="item.width">
{{item.title}}
</li>
</ul>
</div>
<div class="table-tbody">
<div class="body-data">
<!-- tbody -->
<ul v-if="tableData.length" class="th-title tbody-box" v-for="(items, indexs) in tableData" :key="indexs">
<li class="tbody-inner" v-for="(item, index) in viewData" :key="index" :width="item.width">
// 普通文字显示
<span v-if="item.type === 'text'">{{items[item.prop]}}</span>
// 需要传值操作的DOM
<div v-if="item.type === 'setting'">
<slot name="setting" :index="indexs" :tableData="tableData"></slot>
</div>
</li>
// 另起一行的DOM,可以为每一条数据打标签
<div class="label-box">
<slot name="timePicker" :item="items"></slot>
</div>
</ul>
// 空状态
<span v-if="!tableData.length" class="no-data">
{{noData}}
</span>
</div>
</div>
</div>
</template>
<script src="./label.js">
</script>
<style lang="less" src="./label.less">
</style>
js
import $ from 'jquery'
import tools from './../../utils/tools'
export default {
data () {
return {
// 是否限定Tbody的高度
setHiddenHeight: true,
// 空状态文案
noData: this.$attrs && this.$attrs.emptyText
}
},
props: {
// 视图信息,控制表头文案及限定宽度
viewData: {
type: Array,
default: function () {
return []
}
},
// table数据源
tableData: {
type: Array,
default: function () {
return []
}
}
},
// 是否在标签上显示绑定属性
inheritAttrs: false,
watch: {
// 监听数据变化,数据请求完成后重新设置表格宽度
tableData: function () {
this.$nextTick(() => {
this.setDomWidth()
})
}
},
created () {
let attrs = this.attrs
if (attrs && attrs.setHiddenHeight !== 'undefined' && !attrs.setHiddenHeight) {
this.setHiddenHeight = attrs.setHiddenHeight
}
},
methods: {
addSpanData (arr, item, index) {
this.$emit('handle-add-contentToItem', item)
},
setDomWidth () {
let table = $('.table-th')
// 选取表头
let th = $('.th-title')
// 按钮
let btn = $('.tbody-button')
// 表格
let body = $('.table-tbody')
// 全局DOM
let online = $('.table-with-label')[0]
// 接受外部资源定义表格颜色
let attrs = this.$attrs
if (attrs && attrs.thColor) {
table.css('backgroundColor', attrs.thColor)
}
if (attrs && attrs.thBodyColor) {
body.css('backgroundColor', attrs.thBodyColor)
}
// 遍历容器宽度
for (let value of th) {
let title = value.children
// xml格式转Array
title = tools.xmlToArray(title)
// 设置宽度
title.forEach((item, index) => {
let width = item && item.attributes && item.attributes.width && item.attributes.width.nodeValue
item.style.width = width
})
}
let index = 0
// 遍历button颜色
for (let value of btn) {
// let color = value.children
let attributes = value && value.attributes
let color = attributes && attributes.color && attributes.color.value
btn[index].style.backgroundColor = color
index++
}
// js设置tbody高度
if (this.setHiddenHeight) {
let height = online.clientHeight - th[0].clientHeight
body.css('height', height)
}
}
},
mounted () {
this.setDomWidth()
}
}
less
.table-with-label {
width: 100%;
height: 100%;
ul, li {
padding: 0;
margin: 0;
list-style: none;
overflow: hidden;
li {
float: left;
height: 100%;
padding: 10px 0;
line-height: 18px;
overflow: hidden;
text-align: center;
cursor: default;
}
}
// th
.table-th {
width: 100%;
height: auto;
box-sizing: border-box;
background-color: #2A3245;
color: #fff;
font-size: 12px;
.th-title {
height: auto;
}
}
// tbody
.table-tbody {
width: 100%;
box-sizing: border-box;
border-bottom: 1px solid #E0E6ED;
padding-bottom: 10px;
// height: auto;
overflow: auto;
min-height: 80px;
display: inline-block;
font-size: 12px;
color: #1F2D3D;
// button样式
.body-data {
// height: 180px;
overflow: auto;
.tbody-box {
border-bottom: 1px solid #E0E6ED;
// padding-bottom: 10px;
}
.tbody-box:last-child {
border-bottom: 0;
}
.th-title {
.tbody-inner {
.el-button {
padding: 6px 10px;
box-sizing: border-box;
font-size: 12px;
color: #fff;
background-color: #448AFF;
border: 0;
}
.select-span {
font-size: 12px;
color: #448AFF;
}
}
// 标签
.label-box {
width: 100%;
height: auto;
box-sizing: border-box;
padding: 0 30px;
padding-bottom: 10px;
.label-box-inner {
width: 100%;
height: auto;
box-sizing: border-box;
overflow: hidden;
.label-box-title {
width: 10%;
height: 100%;
float: left;
box-sizing: border-box;
cursor: default;
}
.label-box-body {
width: 80%;
height: auto;
float: left;
box-sizing: border-box;
.el-button {
padding: 2px 5px;
font-size: 12px;
color: #757575;
background-color: #EAEAEA;
}
}
}
}
}
// 无数据状态
.no-data {
display: flex;
align-items: center;
justify-content: center;
margin-top: 20px;
font-size: 12px;
color: gray;
}
}
}
}