// el-table 再封装
<template>
<div
class="x-table"
:style="minTableHeight ? `height: calc(100% - ${minTableHeight}px)` : null"
>
<el-table
v-bind="$attrs"
v-on="$listeners"
:data="tableData"
:max-height="tableHeight"
@selection-change="selectionChange"
ref="xTable"
:style="{ '--line': cellLineNumber }"
>
<!-- 多选列 -->
<template v-if="tableConfig.selection" align="left">
<el-table-column
type="selection"
:width="tableConfig.selectionWidth || 40"
:fixed="tableConfig.selectionFixed || null"
></el-table-column>
</template>
<!-- 序号列 -->
<template v-if="tableConfig.index">
<el-table-column
type="index"
:width="tableConfig.indexWidth || 50"
:label="tableConfig.indexLabel || '序号'"
:fixed="tableConfig.indexFixed || null"
></el-table-column>
</template>
<!-- 循环列 -->
<TableTemplate
:tableColumConfig="item"
:key="index"
v-bind="$attrs"
v-on="$listeners"
v-for="(item, index) in tableColumnConfig"
></TableTemplate>
<!-- 提供一个插槽 -->
<slot></slot>
</el-table>
</div>
</template>
<script>
import TableTemplate from "./table-template.vue";
export default {
name: "XTable",
props: {
tableData: {
type: Array,
default: () => [],
},
tableConfig: {
type: Object,
default: () => {},
},
tableColumnConfig: {
type: Array,
require: true,
default: () => [],
},
minusPart: {
type: Number,
default: () => 0,
},
minTableHeight: {
type: Number,
default: () => 0,
},
cellLineNumber: {
type: Number,
default: () => 2,
},
},
data() {
return {
tableHeight: 0,
};
},
mounted() {
this.getTableHeight();
window.addEventListener("resize", this.getTableHeight);
},
beforeMount() {
window.removeEventListener("resize", this.getTableHeight);
},
methods: {
getTableHeight() {
this.$nextTick(() => {
this.tableHeight = window.innerHeight - this.minusPart;
});
},
selectionChange(val) {
this.$emit("selectionChange", val);
},
},
components: { TableTemplate },
};
</script>
<style lang="scss">
.x-table {
.cell {
padding: 0 10px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box; //作为弹性伸缩盒子模型显示。
-webkit-box-orient: vertical; //设置伸缩盒子的子元素排列方式--从上到下垂直排列
-webkit-line-clamp: var(--line); //显示的行
}
th {
background: rgb(240, 242, 245);
}
.x-table-template {
display: flex;
flex-wrap: wrap;
gap: 10px;
justify-content: flex-start;
.x-table-input {
input {
text-align: center;
}
}
}
.el-link {
font-size: 12px;
}
}
</style>
TableTemplate 组件
// 为了实现多级表头而做的子组件的再封装
<template>
<el-table-column
:label="tableColumConfig.label || ''"
:width="tableColumConfig.width || ''"
:min-width="tableColumConfig.minWidth || ''"
:prop="tableColumConfig.prop"
:align="tableColumConfig.align || 'left'"
:header-align="tableColumConfig.headerAlign || 'left'"
:fixed="tableColumConfig.fixed || null"
:sortable="tableColumConfig.sortable || false"
>
<template slot-scope="scope">
<!-- 循环可能存在的template数组 -->
<div
class="x-table-template"
v-if="
tableColumConfig.template &&
Array.isArray(tableColumConfig.template) &&
!tableColumConfig.children
"
:style="tableColumConfig.alignStyle || ''"
>
<div
v-for="(i, _index) in renderItem(
tableColumConfig.template,
scope.row
)"
:key="_index"
>
<!-- 按钮项 -->
<template v-if="i.type === 'button'">
<el-button
:type="i.assemblyType || 'primary'"
:disabled="
i.disabled
? i.disabled({
row: scope.row,
route: $route,
exData: exData,
})
: false
"
@click="
emitFunc(i.method || 'defaultMethod', {
row: scope.row,
index: scope.$index,
additionalParams: i.addParams || '',
})
"
>
{{ i.text }}
</el-button>
</template>
<!-- icon项 -->
<template v-else-if="i.type === 'icon'">
<el-link
:type="i.assemblyType || 'primary'"
:disabled="
i.disabled
? i.disabled({
row: scope.row,
route: $route,
exData: exData,
})
: false
"
@click="
emitFunc(i.method || 'defaultMethod', {
row: scope.row,
index: scope.$index,
additionalParams: i.addParams || '',
})
"
>
<!-- icon的样式 具体看 https://element.eleme.cn/#/zh-CN/component/icon -->
<i :class="i.iconClass"></i>
</el-link>
</template>
<!-- input输入框 -->
<template v-else-if="i.type === 'input'">
<el-input
class="x-table-input"
v-model="scope.row[`${tableColumConfig.prop}`]"
:type="i.assemblyType || 'text'"
:placeholder="i.placeholder || '请输入'"
:disabled="
i.disabled
? i.disabled({
row: scope.row,
route: $route,
exData: exData,
})
: false
"
@blur="
emitFunc(i.method || 'defaultMethod', {
row: scope.row,
index: scope.$index,
additionalParams: i.addParams || '',
})
"
></el-input>
</template>
<!-- 文字方面的 -->
<template v-else-if="i.type === 'link'">
<el-link
:type="i.assemblyType || 'primary'"
:disabled="
i.disabled
? i.disabled({
row: scope.row,
route: $route,
exData: exData,
})
: false
"
@click="
emitFunc(i.method || 'defaultMethod', {
row: scope.row,
index: scope.$index,
additionalParams: i.addParams || '',
})
"
>
{{ i.text }}
</el-link>
</template>
<!-- 非超链接 -->
<template v-else-if="i.type === 'span'">
<span
@click="
emitFunc(i.method || 'defaultMethod', {
row: scope.row,
index: scope.$index,
additionalParams: i.addParams || '',
})
"
:style="i.spanStyle ? i.spanStyle(scope.row) : ''"
>
{{ i.span(scope.row) }}
</span>
</template>
<template v-else-if="i.type === 'render'">
<XTableReder
v-bind="$attrs"
v-on="$listeners"
:sc="scope"
:row="scope.row"
:render="i.render(scope.row, that)"
:rederStyle="i.classStyle ? i.classStyle(scope.row) : ''"
@sss="sss"
></XTableReder>
</template>
<template v-else-if="i.type === 'renderLink'">
<el-link
v-for="(_x, _xindex) in i.renderLink(scope.row)"
:key="_xindex"
@click="
emitFunc(i.method || 'defaultMethod', {
row: scope.row,
index: scope.$index,
additionalParams: i.addParams || '',
linkIndex: _xindex,
})
"
:disabled="
i.disabled
? i.disabled({
row: scope.row,
route: $route,
exData: exData,
})
: false
"
:type="i.assemblyType ? i.assemblyType() : 'primary'"
:style="i.linkStyle"
>
{{ _x }}
</el-link>
</template>
<!-- 自定义值 -->
<el-link
@click="
emitFunc(i.method || 'defaultMethod', {
row: scope.row,
index: scope.$index,
additionalParams: i.addParams || '',
})
"
v-if="i.supplement"
:type="i.suppleType ? i.suppleType(scope.row) : ' '"
:disabled="
i.disabled
? i.disabled({
row: scope.row,
route: $route,
exData: exData,
})
: false
"
>{{ i.supplement(scope.row) }}
</el-link>
</div>
</div>
<template v-else>
{{ scope.row[`${tableColumConfig.prop}`] }}
</template>
</template>
<!-- 可能存在的子集 -->
<template v-if="tableColumConfig.children">
<xtable-template
v-for="(i, __index) in tableColumConfig.children"
:key="__index"
:tableColumConfig="i"
v-bind="$attrs"
v-on="$listeners"
></xtable-template>
</template>
</el-table-column>
</template>
<script>
import XTableReder from "./xTableReder.vue";
export default {
name: "xtable-template",
props: {
tableColumConfig: {
type: Object,
default: () => {},
},
},
computed: {
that() {
return this;
},
exData() {
return window.localStorage.getItem("exData") || "";
},
// 是否渲染模板内的template
renderItem() {
return function (templateList, row) {
if (!Array.isArray(templateList)) {
return [];
}
return templateList.filter((i) => {
return i.showItem
? i.showItem({
row: row,
route: this.$route,
exData: this.exData,
})
: true;
});
};
},
},
methods: {
emitFunc(method, row) {
this.$emit(method, row);
},
},
components: { XTableReder },
};
</script>
<style lang="scss" scoped></style>
//XTableReder 组件
<script>
export default {
functional: true,
props: {
row: {
type: Object,
required: true,
},
render: {
type: Function,
required: true,
},
sc: {
type: Object,
required: true,
},
rederStyle: {
type: String,
require: true,
},
},
render: (h, ctx) => {
const arr = [];
const params = {
row: ctx.props.row,
index: ctx.props.sc.$index,
};
const VNode = ctx.props.render(h, params);
arr.push(VNode);
return h("div", { class: ctx.props.rederStyle }, arr);
},
};
</script>
<template>
<div>
<XTable
class="width:100%"
:tableData="tableData"
:tableConfig="{}"
:minusPart="220"
:minTableHeight="130"
:tableColumnConfig="tableColumnConfig"
@showDialog="showRelationDialog"
@release="release"
@deleteOne="showRelationDialog"
></XTable>
</div>
</template>
<script>
import XTable from "@/components/xTable/index.vue";
export default {
name: "RxdXuzyTestTest01",
components: {
XTable,
},
data() {
return {
tableData: [
{
a: 2,
b: 2,
c: 44,
},
{
a: 1,
b: 3,
c: 45,
},
],
/**
* label number 列名
* width number 列宽
* minWidth number 最小列宽
* prop string 列绑定字段
* align string 列内排序方式 默认 left
* headerAlign string 列头排序方式 默认 left
* fixed string 列的定位布局
* template array template绑定数组
* -----template-----
* type string 组件名 目前支持 btn input icon link
* assemblyType string 组件样式 默认 primary
* disabled boolean 是否禁用 默认 false
* placeholder string input输入框的提示句 默认 请输入
* method string 除了input是blur触发外 其他都是点击触发 默认触发函数是 defaultMethod 请在父元素接收
* text string link和button内显示的文字
* !注意 input默认绑定的是父级的prop
*
*/
tableColumnConfig: [
{
label: "模型名称",
prop: "modelName",
},
{
label: "更新时间",
prop: "updateTime",
},
{
label: "脚本编码",
prop: "scriptCode",
},
{
label: "关联采集",
prop: "configId",
template: [
{
supplement: (row) => {
const str = row.configId || "";
const strList = str.split(",");
return strList.length;
},
},
],
},
{
label: "模型描述",
prop: "modelDesc",
},
{
label: "审批状态",
template: [
{
type: "span",
span: (row) => statusOptions[row.status].label || "",
},
],
},
{
label: "操作",
width: "165px",
fixed: "right",
headerAlign: "center",
alignStyle: "justify-content: center;",
template: [
{
type: "link",
text: "详情",
method: "showDialog",
addParams: 1,
},
{
type: "link",
text: "编辑",
method: "showDialog",
addParams: 2,
disabled: ({ row }) => row.status == 1,
},
{
type: "link",
text: "删除",
method: "deleteOne",
addParams: -1,
disabled: ({ row }) => row.status == 1,
},
// {
// type: "link",
// text: "发布",
// method: "release",
// disabled: ({ row }) => row.status != 0,
// showItem: () => {
// const roleArr =
// JSON.parse(window.localStorage.getItem("roleArr")) || [];
// return roleArr.includes("model_manage");
// },
// },
],
},
{
label: "动态渲染",
template: [
{
type: "render",
render: (row, vue) => {
function onClick() {
vue.$emit("sss");
}
return function (h, ctx) {
return <el-link onClick={onClick}>哈哈</el-link>;
};
},
classStyle: (row) => "",
},
],
},
],
tableConfig: {
index: true, //是否需要index列
indexWidth: 60, //index列宽
indexLabel: "序号", //index列label
indexFixed: "left", //index列是否开启fixed布局,如写则开启
selection: true, //是否需要多选列
selectionWidth: 60, //多选列宽
selectionFixed: "left", //index列是否开启fixed布局,如写则开启
},
};
},
mounted() {},
methods: {
showSomeThing({ row = {}, index = 0 }) {
console.log(row);
console.log(index);
},
},
};
</script>
<style lang="scss" scoped></style>
tableConfig: {
stripe: true, //是否开启斑马纹
border: true, //是否开启边框
index: true, //是否需要index列
indexWidth: 60, //index列宽
indexLabel: "序号", //index列label
indexFixed: "left", //index列是否开启fixed布局,如写则开启
selection: true, //是否需要多选列
selectionWidth: 60, //多选列宽
selection: "left", //index列是否开启fixed布局,如写则开启
},
tableColumnConfig: [
{
label: "h",
prop: "a",
align: "center",
headerAlign: "center",
},
{
label: "s",
prop: "b",
template: [
{
type: "input",
prop: "b",
method: "showSomeThing",
},
{
type: "button",
text: "b",
method: "showSomeThing",
},
],
},
],
// 接收自定义的子组件事件
showSomeThing({ row = {}, index = 0 }) {
console.log(row);
console.log(index);
},
* label number 列名
* width number 列宽
* minWidth number 最小列宽
* prop string 列绑定字段
* align string 列内排序方式 默认 left
* headerAlign string 列头排序方式 默认 left
* fixed string 列的定位布局
* template array template绑定数组
* -----template-----
* type string 组件名 目前支持 btn input icon link
* assemblyType string 组件样式 默认 primary
* disabled boolean 是否禁用 默认 false
* placeholder string input输入框的提示句 默认 请输入
* method string 除了input是blur触发外 其他都是点击触发 默认触发函数是 defaultMethod 请在父元素接收
* text string link和button内显示的文字
* !注意 input默认绑定的是父级的prop
*
修改了一下绑定方式 ,可以直接在调用组件里使用 el-table 的api了同时支持了 render 渲染 这个组件的开发暂时告一段落了
gitee仓库地址