一步一步教你封装一个可配置的table组件(vue)__Vue.js
发布于 4 年前 作者 banyungong 2879 次浏览 来自 分享
粉丝福利 : 关注VUE中文社区公众号,回复视频领取粉丝福利

组件需求

  • 传一个columns配置文件,即可生成对应的table
  • 传一个data即可渲染对应的数据
  • 可通过插槽的方式对数据进行二次处理

组件设计

  • columns是一个数组类型(必须)

  • columns里面每一项是一个对象(必须)

  • columns每个对象应该包含:

    • title(String):根据这个键生成的thead对应的th(必填)
    • dataIndex (String): 根据这个键渲染对象的数据(这个键跟data里面的键一一对应)(必填)
    • customRender(Boolean):根据这个键判断是否要分配一个对应的插槽(可选)
  • data是一个数组类型(必须)

  • data里面每一项是一个对象,里面的键必须跟上面的columns的dataIndex一一对应(必须)

期待的使用方式


<y-table :columns="columns" :data="data">
  <template #sex="text">
    {{ text === 1 ? '男': '女'}}
  </template>
  <template #handle="text,record">
    <div style="display:flex">
      <y-button type='success' @click="test(record)" style="margin-right:10px">修改</y-button>
      <y-button type='danger' @click="test(record)">删除</y-button>
    </div>
  </template>
</y-table>

<script>
  data () {
    return {
      columns: [
        {
          title: '名字',
          dataIndex: 'name'
        },
        {
          title: '年龄',
          dataIndex: 'age'
        },
        {
          title: '性别',
          dataIndex: 'sex',
          customRender: true
        },
        {
          title: '操作',
          dataIndex: 'handle',
          customRender: true
        }
      ],
      data: [
        {
          name: '鸡太美',
          age: 39,
          sex: 1,
          reload: 3
        },
        {
          name: '鸡太美2',
          age: 39,
          sex: 2,
          reload: 3
        }
      ]
    }
  }
</script>

期待的效果

组件的实现

首先根据上面的的需求,先定义两个props


props: {
    columns: {
      type: Array,
      required: true
    },
    data: {
      type: Array,
      default: () => []
    }
  }

接着根据传进来的columns的title生成对应的thead

// 根据配置生成thead
_renderHeader (h) {
  return h('thead', { class: 'y-header' }, [
    h('tr', { class: 'y-header-row' }, [
      this.columns.map(row => {
        return h('th', { class: ['y-header-column', 'y-table-left'] }, row.title)
      })
    ])
  ])
}

紧接着,根据columns的dataIndex结合data的键值对渲染对应的数据,再根据columns的customRender判断是否分配对应的插槽

// 根据配置生成tbody,再根据customRender分配作用域插槽
_renderBody (h) {
  return h('tbody', {}, [
    this.data.map(row => {
      return h('tr', { class: 'y-body-row' }, [
        this.columns.map(item => {
          return h('td', { class: 'y-body-column' }, item.customRender && this.$scopedSlots[item.dataIndex]
            ? this.$scopedSlots[item.dataIndex](row[item.dataIndex], {
              ...row
            }) : row[item.dataIndex])
        })
      ])
    })
  ])
}

这里生成的插槽是作用域插槽,有时候它是封装组件的神一样的存在,这里把当前的值传给插槽的第一参数,当前的行数据传给第二参数,所以外面就可以这样拿到数据

 <template #handle="text,record">
    <div style="display:flex">
      <y-button type='success' @click="test(record)" style="margin-right:10px">修改</y-button>
      <y-button type='danger' @click="test(record)">删除</y-button>
    </div>
  </template>

最后组装table,return 出去就OK了

// 组装table
  _renderTable (h) {
    return (
      <table class='y-table'>
        {this._renderHeader(h)}
        {this._renderBody(h)}
      </table>
    )
  }

  render (h) {
    return (
      this._renderTable(h)
    )
  }

总结

到此,根据上面的需求已经实现了对应的可配置的table组件,比较核心的是上面两个生成方法(_renderHeader,_renderBody)大概也就20行,对于熟悉的JSX和作用域插槽的同学来说再容易不过了。 有兴趣的同学可以继续根据自己的需要拓展自己需要的table组件。

        版权声明:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
        作者: Napoleon
        原文链接:<a href='https://juejin.im/post/6868960483685171208'>https://juejin.im/post/6868960483685171208</a>
      </p>
回到顶部