我们在用vue + element-ui写后台管理系统项目时,table组件应该是用的频率非常高的组件之一,但是我们不希望每次都使用element-ui的表格代码,秉着代码可读性和可复用性的原则,我们需要对element的table组件进行二次封装。
<template>
<Table :data="tableData" style="width:100%">
<template v-for="column in columns">
<TableColumn :key="column.prop" :prop="column.prop" :label="column.title" v-if="!column.action"/>
// 操作列
<TableColumn :label="column.title" v-else>
<template slot-scope="scope">
<template v-for="(fn,index) in column.actions">
<Divider direction="vertical" v-if="index>0"/>
<Button type="text" @click="handleClick(scope.row,fn.fnName)">{{fn.title}}</Button>
</template>
</template>
</TableColumn>
</template>
</Table>
</template>
<script>
import {Table, TableColumn,Divider,Button} from 'element-ui'
export default {
name: "tableC",
components: {Table, TableColumn,Divider,Button},
props: {
columns: {
required: true, type: Array, default: () => {
return []
}
},
tableData: {
required: true,
type: Array,
default: () => {
return []
}
}
},
methods:{
handleClick(row,fnName){
this.$emit(`${fnName}`,row)
}
}
};
</script>
<template>
<TableC :columns="columns" :tableData="tableData" @add="add" @edit="edit"></TableC>
</template>
<script>
import TableC from "./table";
export default {
name: "list",
components: {TableC},
data() {
return {
columns: [
{prop: 'id', title: 'id'},
{prop: 'name', title: '姓名'},
{action: true, title: '操作', actions: [{fnName: 'add', title: '新增'}, {fnName: 'edit', title: '编辑'}]}
],
tableData: [
{id:'1267823566512bdh',name: 'chenkai'},
{id:'qweq12312312',name: 'eqwe'},
]
};
},
methods: {
add(e) {
console.log('新增:' + e.name);
},
edit(e) {
console.log('编辑:' + e.name);
}
}
};
</script>
可以看到,操作列的数据,我定义了是否为action的标识,操作的按钮数据通过actions的数组传入,其中fnName为方法名,title为按钮文字,子组件中通过$emit提交对应的方法,父组件中监听对应的方法即可。
这样,我们就完成了对table组件基本的二次封装。
但是,实际的业务场景中,这个组件并不能满足我们的开发需求,例如:某个列需要以链接的形式展示或者需要展示例如Switch的组件,这种情况下,上面的组件就不能满足我们的需求。所以,我们还得继续对组件进行优化。
话不多说,直接上代码
<template>
<Table :data="tableData" style="width:100%">
<template v-for="column in columns">
<TableColumn :key="column.prop" :prop="column.prop" :label="column.title" v-if="!column.action">
<template slot-scope="scope">
<slot v-if="column.slot" :name="column.prop" :row='scope.row'/>
<span v-else>{{ scope.row[column.prop] }}</span>
</template>
</TableColumn>
<TableColumn :label="column.title" v-else>
<template slot-scope="scope">
<template v-for="(fn,index) in column.actions">
<Divider direction="vertical" v-if="index>0"/>
<Button type="text" @click="handleClick(scope.row,fn.fnName)">{{fn.title}}</Button>
</template>
</template>
</TableColumn>
</template>
</Table>
</template>
这里我用slot插槽的方式来接收内容
页面调用代码改动
<TableC :columns="columns" :tableData="tableData" @add="add" @edit="edit">
<template slot='id' slot-scope="scope">
<a href="#">{{scope.row.id}}</a>
</template>
</TableC>
columns: [
{prop: 'id', title: 'id', slot: true},
{prop: 'name', title: '姓名'},
{action: true, title: '操作', actions: [{fnName: 'add', title: '新增'}, {fnName: 'edit', title: '编辑'}]}
],
以下为实际展示效果
至此,我们的组件已经改造完成,这种方式能够满足我们绝大多数的业务场景,如有好的想法或者更好的改造方式,欢迎提出。