VUE封装Table组件

3,831 阅读4分钟

table组件封装

1 Table组件封装思路

  1. 首先先用table-item.vue接受两个cloumns 、 data,将数据渲染出来,搭建基本的组件模板
  2. 通过render + jsx完成自定义render渲染, 在render.js中接受index、 cloumn, row, render四个props
  3. 通过添加个性化需求,完善组件

2 Table组件开发

1 基本的组件模板

  • 创建table-item.vue,添加columnsdataprops属性,这里的关键是遍历后的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组件,传入columnsdata数据

    <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函数渲染

  • 修改testTablecloumns数据

    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>

接下来再补上单选,多选,以及合并单元格等操作

参考 组件精讲以及自己公司项目