table组件封装
1 Table组件封装思路
- 首先先用
table-item.vue接受两个cloumns 、 data,将数据渲染出来,搭建基本的组件模板 - 通过
render+jsx完成自定义render渲染, 在render.js中接受index、 cloumn, row, render四个props - 通过添加个性化需求,完善组件
2 Table组件开发
1 基本的组件模板
-
创建
table-item.vue,添加columns、data的props属性,这里的关键是遍历后的data数组中值,可由columns遍历的key值获取渲染,即{{row[col[key]]}}<template> <div class="table-item"> <table> <thead> <tr> <th v-for="(item, key) in columns" :key="key" >{{ item.title }}</th> </tr> </thead> <tbody> <tr v-for="(row, key1) in data" :key="key1" > <td v-for="(col, key2) in columns" :key="key2" > {{ row[col.key] }} </td> </tr> </tbody> </table> </div> </template> <script> import Render from './table.js'; export default { // table 组件编写 components: {Render}, props: { columns: { type: Array, require: true, default(){ return [] } }, data: { type: Array, require: true, default(){ return [] } } } } </script> <style scoped> table{ width: 100%; border-collapse: collapse; border-spacing: 0; empty-cells: show; border: 1px solid #e9e9e9; } table th{ background: #f7f7f7; color: #5c6b77; font-weight: 600; white-space: nowrap; } table td, table th{ padding: 8px 16px; border: 1px solid #e9e9e9; text-align: left; } </style>这种处理对象的值需要根据数组中的key值来显示的地方,在很多场景都能使用,比如
<template> <div v-for="(item, key) in dataList">{{ formData[item.key] }}</div> </template> <script> // formData的数据可以是从服务器推送过来的json数据,需要遍历在其他地方,就可以用这种方法,而不用去解构,既能初始化数据,还能一次性提交修改的formData数据。 </script> -
创建路由文件入口
testTable.vue引入table-item.vue组件,传入columns、data数据<template> <div> <table-item :columns="columns" :data="dataList"></table-item> </div> </template> <script> import TableItem from '../component/table/table-item.vue' export default { components: { TableItem }, data() { return { columns: [ { title: '姓名', key: 'name', }, { title: '年龄', key: 'age' }, { title: '出生日期', key: 'birthday' }, { title: '地址', key: 'address' }, { title: '操作' } ], dataList: [ { name: '王小明', age: 18, birthday: '919526400000', address: '北京市朝阳区芍药居' }, { name: '张小刚', age: 25, birthday: '696096000000', address: '北京市海淀区西二旗' }, { name: '李小红', age: 30, birthday: '563472000000', address: '上海市浦东新区世纪大道' }, { name: '周小伟', age: 26, birthday: '687024000000', address: '深圳市南山区深南大道' } ] } } } </script> <style> </style> -
基本的组件模板样式就完成了
2 render自定义模板
-
创建
table.js文件,采用函数式组件方式,functional=true, 类似react的无状态组件// 创建一个函数式组件 Functional = true export default { functional: true, // 接受四个参数 row , column, index, render props: { row: Object, // 当前行的数据 column: Object, // 当前列的数据 index: Number, // 当前是第几行 render: Function, // 具体的函数内容 }, render(h, ctx) { // console.log(h, ctx) // 将row , column, index 合并 const params = { row: ctx.props.row, column: ctx.props.column, index: ctx.props.index } return ctx.props.render(h, params); } }这里采用函数式组件渲染,在
render函数中已经没有this这些属性,只有上下文ctx,可以从ctx中获取需要的属性及方法。详细地参考vue函数渲染 -
修改
testTable中cloumns数据columns: [ { title: '姓名', key: 'name', render:(h, params) => { const str = params.row.name return h('span', str) } }, { title: '年龄', key: 'age' }, { title: '出生日期', key: 'birthday' }, { title: '地址', key: 'address' }, { title: '操作' } ], -
同样,需要在
table-item中修改渲染方式,如果有render属性就走render组件,没有就走默认span<!--省略部分代码--> <td v-for="(col, key2) in columns" :key="key2" > <template v-if="col.render"> <Render :column="col" :row="row" :index="key1" :render="col.render"></Render> </template> <template v-else> {{ row[col.key] }} </template> </td>
3 结合jsx配置render
-
直接采用
jsx是不行的,需要通过babel编译后才能使用jsx语法 -
安装相关插件依赖
npm i babel-plugin-syntax-jsx babel-plugin-transform-vue-jsx babel-helper-vue-jsx-merge-props --save -
在
.babelrc配置jsx{ "presets": [ ["env", { "modules": false }], ], "plugins": ["transform-vue-jsx"] } -
配置完就能使用
jsx语法来编写render函数了{ title: '姓名', key: 'name', render: (h, params) => { // return h('span', '郭大侠') return ( <p> <span>{params.row.name}</span> </p> ) } },
4 简单实现click操作
<template>
<div>
<table-item :columns="columns" :data="dataList"></table-item>
</div>
</template>
<script>
import TableItem from '../component/table/table-item.vue'
export default {
components: {
TableItem
},
data() {
return {
columns: [
{
title: '姓名',
key: 'name',
render: (h, params) => {
return (
<p>
<span>{params.row.name}</span>
</p>
)
}
},
{
title: '年龄',
key: 'age'
},
{
title: '出生日期',
key: 'birthday'
},
{
title: '地址',
key: 'address'
},
{
title: '操作',
render: (h, params) => {
return (<el-button onClick={() => {this.handleClick()}}>操作</el-button>)
}
}
],
dataList: [
{
name: '王小明',
age: 18,
birthday: '919526400000',
address: '北京市朝阳区芍药居'
},
{
name: '张小刚',
age: 25,
birthday: '696096000000',
address: '北京市海淀区西二旗'
},
{
name: '李小红',
age: 30,
birthday: '563472000000',
address: '上海市浦东新区世纪大道'
},
{
name: '周小伟',
age: 26,
birthday: '687024000000',
address: '深圳市南山区深南大道'
}
]
}
},
methods: {
handleClick() {
console.log(1234)
}
}
}
</script>
<style>
</style>
接下来再补上单选,多选,以及合并单元格等操作
参考 组件精讲以及自己公司项目