封装element-ui表格,我是这样作的

日日加班至夜半,环视周围无人走; 明晚八点准时走,谁不打卡谁是狗。前端

使用过element-ui的表格的同窗应该都有这样的体会,作一个简单的表格还比较容易,但若是这个表格包含了顶部的按钮,还有分页,甚至再包含了行编辑,那开发工做量就成倍的增长,特别是在开发管理系统的时候,表格一个接一个的去开发, 即浪费时间,还对我的没有什么提高。今天小编带来了本身封装的一个表格,让你用JSON就能够简单的生成表格。vue

本文主要集中于封装思想与核心代码说明,完整代码请访问 github.com/snowzijun/v…,若是以为有用,麻烦给小编一个star,你的每个star都是对小编的支持,当前功能比较简陋,本仓库将持续更新。同时您也能够微信搜索【前端有的玩】公众号,与小编进行沟通。git

表格需求

通常管理系统对表格会有如下需求github

  1. 能够分页(须要有分页条)
  2. 能够多选(表格带复选框)
  3. 顶部须要加一些操做按钮(新增,删除等等)
  4. 表格每行行尾有操做按钮
  5. 表格行能够编辑

以下图为一个示例表格npm

若是咱们直接使用element-ui提供的组件的话,那么开发一个这样的表格就须要使用到如下内容element-ui

  1. 须要使用表格的插槽功能,开发每一行的按钮
  2. 须要经过样式调整顶部按钮,表格,分页条的布局样式
  3. 须要监听分页的事件而后去刷新表格数据
  4. 顶部按钮或操做按钮若是须要获取表格数据,须要调用表格提供的api
  5. 对于有行编辑的需求,还须要经过插槽去渲染行编辑的内容,同时要控制行编辑的开关

不只仅开发表格比较麻烦,并且还要考虑团队协做,若是每一个人实现表格的方式存在差异,那么可能后期的维护成本也会变得很高。那怎么办呢?api

项目安装

安装插件

在使用element-ui的项目中,能够经过如下命令进行安装数组

npm install vue-elementui-table -S
复制代码

在项目中使用

main.js中添加如下代码微信

import ZjTable from 'vue-elementui-table'
 Vue.use(ZjTable) 复制代码

而后便可像下文中的使用方式进行使用markdown

表格配置

为了知足团队快速开发的须要,小编对上面提出来的需求进行了封装,而后使用的时候,开发人员只须要配置一些JSON即可以完成以上功能的开发。

基础配置

一个基础的表格包含了数据和列信息,那么如何用封装的表格去配置呢?

<template> <zj-table :columns="columns" :data="data" :pagination="false" /> </template> <script> export default { data() { return { // 表格的列信息, 数组每一项表明一个字段,可使用element 列属性的全部属性,如下仅为示例 columns: Object.freeze([ { // 表头显示的文字 label: '姓名', // 对应数据里面的字段 prop: 'name' }, { label: '性别', prop: 'sex', // 格式化表格,与element-ui 的表格属性相同 formatter(row, column, cellValue) { return cellValue === 1 ? '男' : '女' } }, { label: '年龄', prop: 'age' } ]), data: [ { name: '子君', sex: 1, age: 18 } ] } } } </script> 复制代码

经过上面的配置,就能够完成一个基础表格的开发,完整代码见 github.com/snowzijun/v…,效果以下图所示

表格默认会显示复选框,也能够经过配置selectable属性来关闭掉

添加分页

简单的表格用封装以后的或未封装的开发工做量区别并不大,咱们继续为表格添加上分页

<template>
	<!--
    current-page.sync 表示页码, 添加上 .sync 在页码发生变化时自动同步页码
    page-size.sync 每页条数
    total  总条数
    height="auto" 配置height:auto, 表格高度会根据内容自动调整,若是不指定,表格将保持充满父容器,同时表头会固定,不跟随滚动条滚动
    @page-change 不管pageSize currentPage 哪个变化,都会触发这个事件
  -->
  <zj-table
    v-loading="loading"
    :columns="columns"
    :data="data"
    :current-page.sync="currentPage"
    :page-size.sync="pageSize"
    :total="total"
    height="auto"
    @page-change="$_handlePageChange"
  />
</template>
<script>
export default {
  data() {
    return {
      columns: Object.freeze([
        // 列字段与上例同样,此处省略
      ]),
      data: [],
      // 当前页码
      currentPage: 1,
      // 每页条数
      pageSize: 10,
      // 总条数
      total: 0,
      // 是否显示loading
      loading: false
    }
  },
  created() {
    this.loadData()
  },
  methods: {
    // 加载表格数据
    loadData() {
      this.loading = true
      setTimeout(() => {
        // 假设总条数是40条
        this.total = 40
        const { currentPage, pageSize } = this
        // 模拟数据请求获取数据
        this.data = new Array(pageSize).fill({}).map((item, index) => {
          return {
            name: `子君${currentPage + (index + 1) * 10}`,
            sex: Math.random() > 0.5 ? 1 : 0,
            age: Math.floor(Math.random() * 100)
          }
        })
        this.loading = false
      }, 1000)
    },
    $_handlePageChange() {
      // 由于上面设置属性指定了.sync,因此这两个属性会自动变化
      console.log(this.pageSize, this.currentPage)
      // 分页发生变化,从新请求数据
      this.loadData()
    }
  }
}
</script>
复制代码

完整代码请参考 github.com/snowzijun/v…

经过封装,表格将自带分页功能,经过上面代码,实现效果以下所示,是否是变得简单了一些。接下来咱们继续给表格添加按钮

添加顶部按钮

表格上面可能会有新增,删除等等按钮,怎么办呢,接下来咱们继续经过配置去添加按钮

<template> <zj-table :buttons="buttons" /> </template> <script> export default { data() { return { buttons: Object.freeze([ { // id 必须有并且是在当前按钮数组里面是惟一的 id: 'add', text: '新增', type: 'primary', icon: 'el-icon-circle-plus', click: this.$_handleAdd }, { id: 'delete', text: '删除', // rows 是表格选中的行,若是没有选中行,则禁用删除按钮, disabled能够是一个boolean值或者函数 disabled: rows => !rows.length, click: this.$_handleRemove }, { id: 'auth', text: '这个按钮根据权限显示', // 能够经过返回 true/false来控制按钮是否显示 before: (/** rows */) => { return true } }, // 能够配置下拉按钮哦 { id: 'dropdown', text: '下拉按钮', children: [ { id: 'moveUp', text: '上移', icon: 'el-icon-arrow-up', click: () => { console.log('上移') } }, { id: 'moveDown', text: '下移', icon: 'el-icon-arrow-down', disabled: rows => !rows.length, click: () => { console.log('下移') } } ] } ]) } }, created() {}, methods: { // 新增 $_handleAdd() { this.$alert('点击了新增按钮') }, // 顶部按钮会自动将表格所选的行传出来 $_handleRemove(rows) { const ids = rows.map(({ id }) => id) this.$alert(`要删除的行id为${ids.join(',')}`) }, // 关注做者公众号 $_handleFollowAuthor() {} } } </script> 复制代码

表格顶部能够添加普通的按钮,也能够添加下拉按钮,同时还能够经过before来配置按钮是否显示,disabled来配置按钮是否禁用,上面完整代码见 github.com/snowzijun/v…

经过上面的代码就能够配置出下面的表格,是否是很简单呢?

表格顶部能够有按钮,行尾也是能够添加按钮的,一块儿来看看

行操做按钮

通常咱们会将一些单行操做的按钮放在行尾,好比编辑,下载等按钮,那如何给行尾配置按钮呢?

<template>
 <zj-table  :columns="columns"  /> </template> <script> export default {  data() {  return {  columns: Object.freeze([  {  // 能够指定列的宽度,与element-ui原生用法一致  width: 220,  label: '姓名',  prop: 'name'  },  // 行编辑按钮,在表格末尾出现,自动锁定右侧  {  width: 180,  label: '操做',  // 经过 actions 指定行尾按钮  actions: [  {  id: 'follow',  text: '关注做者',  click: this.$_handleFollowAuthor  },  {  id: 'edit',  text: '编辑',  // 能够经过before控制按钮是否显示,好比下面年龄四十岁的才会显示编辑按钮  before(row) {  return row.age < 40  },  click: this.$_handleEdit  },  {  id: 'delete',  text: '删除',  icon: 'el-icon-delete',  disabled(row) {  return row.sex === 0  },  // 为了拿到this,这里须要用箭头函数  click: () => {  this.$alert('女生被禁止删除了')  }  }  ]  }  ])  }  },  methods: {  // 关注做者公众号  $_handleFollowAuthor() {  console.log('微信搜索【前端有的玩】,这是对小编最大的支持')  },  /**  * row 这一行的数据  */  $_handleEdit(row, column) {  this.$alert(`点击了姓名为【${row.name}】的行上的按钮`)  }  } } </script>  复制代码

行操做按钮会被冻结到表格最右侧,不会跟随滚动条滚动而滚动,上面完整代码见, github.com/snowzijun/v…

经过上面的代码就能够完成如下效果

最后再来一块儿看看行编辑

行编辑

好比上例,我但愿点击行尾的编辑按钮的时候,能够直接在行上面编辑用户的姓名与性别,如何配置呢?

<template>
 <zj-table  ref="table"  :columns="columns"  :data="data"  /> </template> <script> export default {  data() {  return {  columns: Object.freeze([  {  label: '姓名',  prop: 'name',  editable: true,  field: {  componentType: 'input',  rules: [  {  required: true,  message: '请输入姓名'  }  ]  }  },  {  label: '性别',  prop: 'sex',  // 格式化表格,与element-ui 的表格属性相同  formatter(row, column, cellValue) {  return cellValue === '1' ? '男' : '女'  },  editable: true,  field: {  componentType: 'select',  options: [  {  label: '男',  value: '1'  },  {  label: '女',  value: '0'  }  ]  }  },  {  label: '年龄',  prop: 'age',  editable: true,  field: {  componentType: 'number'  }  },  {  label: '操做',  actions: [  {  id: 'edit',  text: '编辑',  // 若是当前行启用了编辑,则不显示编辑按钮  before: row => {  return !this.editIds.includes(row.id)  },  click: this.$_handleEdit  },  {  id: 'save',  text: '保存',  // 若是当前行启用了编辑,则显示保存按钮  before: row => {  return this.editIds.includes(row.id)  },  click: this.$_handleSave  }  ]  }  ]),  data: [  {  // 行编辑必须指定rowKey字段,默认是id,若是修改成其余字段,须要给表格指定row-key="字段名"  id: '0',  name: '子君',  sex: '1',  age: 18  },  {  // 行编辑必须指定rowKey字段,默认是id,若是修改成其余字段,须要给表格指定row-key="字段名"  id: '1',  name: '子君1',  sex: '0',  age: 18  }  ],  editIds: []  }  },  methods: {  $_handleEdit(row) {  // 经过调用 startEditRow 能够开启行编辑  this.$refs.table.startEditRow(row.id)  // 记录开启了行编辑的id  this.editIds.push(row.id)  },  $_handleSave(row) {  // 点击保存的时候,经过endEditRow 结束行编辑  this.$refs.table.endEditRow(row.id, (valid, result, oldRow) => {  // 若是有表单验证,则valid会返回是否验证成功  if (valid) {  console.log('修改以后的数据', result)  console.log('原始数据', oldRow)  const index = this.editIds.findIndex(item => item === row.id)  this.editIds.splice(index, 1)  } else {  // 若是校验失败,则返回校验的第一个输入框的异常信息  console.log(result)  this.$message.error(result.message)  }  })  }  } } </script>  复制代码

不须要使用插槽就能够完成行编辑,是否是很开心。上述完整代码见 github.com/snowzijun/v…

效果以下图所示:

其余功能

除了上面的功能以外,表格还能够配置其余许多功能,好比

  1. 能够指定字段为连接列,须要给列配置link属性
  2. 能够经过插槽自定义顶部按钮,行操做按钮,行字段等
  3. 能够在按钮区域右侧经过插槽配置其余内容
  4. 其余等等

表格开发说明

经过上面的代码示例,咱们已经知道了封装以后的表格能够完成哪些事情,接下来一块儿来看看表格是如何实现的。完整代码见 github.com/snowzijun/v…

表格布局

整个表格是经过JSX来封装的,由于JSX使用起来更加灵活。对于咱们封装的表格,咱们从竖向能够分为三部分,分别是顶部按钮区,中间表格区,底部分页区,如何去实现三个区域的布局呢,核心代码以下

render(h) {
 // 按钮区域  const toolbar = this.$_renderToolbar(h)  // 表格区域  const table = this.$_renderTable(h)  // 分页区域  const page = this.$_renderPage(h)   return (  <div class="zj-table" style={{ height: this.tableContainerHeight }}>  {toolbar}  {table}  {page}  </div>  )  } 复制代码

经过三个render函数分别渲染对应区域,而后将三个区域组合在一块儿。

渲染表格列

经过前文的讲解,咱们能够将表格的列分为如下几种

  1. 常规列
  2. 行编辑列
  3. 操做按钮列
  4. 插槽列
  5. 连接列(文档后续完善)
  6. 嵌套列(文档后续完善)
$_renderColumns(h, columns) {
 // 总体是否排序  let sortable = this.sortable ? 'custom' : false  return columns  .filter(column => {  const { hidden } = column  if (hidden !== undefined) {  if (typeof hidden === 'function') {  return hidden({  columns,  column  })  }  return hidden  }  return true  })  .map(column => {  const {  useSlot = false,  // 若是存在操做按钮,则actions为非空数组  actions = [],  // 是否可编辑列, 对于可编辑列须要动态启用编辑  editable = false,  // 是否有嵌套列  nests,  // 是否可点击  link = false  } = column  let newSortable = sortable  if (column.sortable !== undefined) {  newSortable = column.sortable ? 'custom' : false  }  column = {  ...column,  sortable: newSortable  }  if (nests && nests.length) {  // 使用嵌套列  return this.$_renderNestColumn(h, column)  } else if (editable) {  // 使用编辑列  return this.$_renderEditColumn(h, column)  } else if (useSlot) {  // 使用插槽列  return this.$_renderSlotColumn(h, column)  } else if (actions && actions.length > 0) {  // 使用操做列  column.sortable = false  return this.$_renderActionColumn(h, column)  } else if (link) {  // 使用连接列  return this.$_renderLinkColumn(h, column)  } else {  // 使用默认列  return this.$_renderDefaultColumn(h, column)  }  })  }, 复制代码

行编辑列

当前表格行编辑支持input,select,datepicker,TimeSelect,InputNumber等组件,具体渲染代码以下所示

// 编辑单元格
 $_renderEditCell(h, field) {  const components = {  input: Input,  select: ZjSelect,  date: DatePicker,  time: TimeSelect,  number: InputNumber  }  const componentType = field.componentType  const component = components[componentType]  if (component) {  return this.$_renderField(h, field, component)  } else if (componentType === 'custom') {  // 若是自定义,能够经过component指定组件  return this.$_renderField(h, field, field.component)  }  return this.$_renderField(h, field, Input)  },  $_renderField(h, field, Component) {  // 编辑行的id字段  const { rowId, events = {}, nativeEvents = {} } = field   const getEvents = events => {  const newEvents = {}  Object.keys(events).forEach(key => {  const event = events[key]  newEvents[key] = (...rest) => {  const args = [  ...rest,  {  rowId,  row: this.editRowsData[rowId],  value: this.editRowsData[rowId][field.prop]  }  ]  return event(...args)  }  })  return newEvents  }  // 事件改写  const newEvents = getEvents(events)  const newNativeEvents = getEvents(nativeEvents)  return (  <Component  size="small"  on={newEvents}  nativeOn={newNativeEvents}  v-model={this.editRowsData[rowId][field.prop]}  {...{  attrs: field,  props: field  }}  />  )  } 复制代码

总结

这个表格包含了许多功能,文章长度优先,若是以为有用,能够经过访问 github.com/snowzijun/v… 查看完整代码,本仓库代码及文档小编将持续完善,欢迎star。缘始积累,关注公众号,小编拉你进前端交流群

阅读小编近期的热门Vue相关文章,我是子君,每周一,不见不散

实战技巧,Vue原来还能够这样写 获赞 2700+

绝对干货~!学会这些Vue小技巧,能够早点下班和女神约会了 获赞 1200+

前方高能,这是最新的一波Vue实战技巧,不用则已,一用惊人 获赞 1000+

我在项目中是这样配置Vue的 获赞 1000+

学会使用Vue JSX,一车老干妈都是你的 获赞700+

让Vue项目更丝滑的几个小技巧 获赞 300+

看到赚到!重读vue2.0风格指南,我整理了这些关键规则 获赞 150+

结语

不要吹灭你的灵感和你的想象力; 不要成为你的模型的奴隶。 ——文森特・梵高

本文使用 mdnice 排版

相关文章
相关标签/搜索