欢迎来到代码驿站!

vue

当前位置:首页 > 网页前端 > vue

Vue封装通用table组件的完整步骤记录

时间:2022-06-25 08:06:49|栏目:vue|点击:

前言

随着业务的发展和功能的增多,我们发现不少页面都具备相似的功能,这里举几个比较俗的例子:可以多选的下拉菜单,带输入的对话框,日期选择器等等,于是我们会想办法将这些共有的功能抽取成一个个公共组件,以便能够在不同的页面或业务中使用。

为什么需要封装table组件?

后台管理系统表格使用频率高,减少关于table的业务代码,且便于后期统一修改、便于后期维护。如给table内容展示,超出单元格以省略号展示等。

对于大部分的后台管理系统,数据表格的展示大同小异,由于不想写重复的代码,所以我选择封装通用table组件,解放双手。如果你的表格有一列并不是简单dom元素,比如switch按钮,完全可以传入一个render函数,来达到目的。

第一步:定义通用组件

<!-- pro-table.vue -->
<template>
  <div>
    <el-table
      :data="tableData"
      style="width: 100%"
      :stripe="tableTitle.stripe"
      :border="tableTitle.border"
      :fit="tableTitle.fit"
      :highlight-current-row="tableTitle.highlightCurrentRow"
      @selection-change="handleSelectionChange">
      <!--表格第一列-->
      <el-table-column
        :type="firstTableCol.type"
        :width="firstTableCol.width"
        v-if="firstTableCol.select"
      >
      </el-table-column>
      <!--表格其它列-->
      <el-table-column v-for="(value,index) in tableCol" :key="index"
                       :prop="value.prop"
                       :label="value.label"
                       :width="value.width || 180">
        <template slot-scope="scope">
          <template v-if="!value.render">
            <template v-if="value.formatter">
              {{ value.formatter(scope.row, value) }}
            </template>
            <template v-else-if="value.getImgurl">
              <el-image :src="value.getImgurl(scope.row, value)" style="width: 70px; height: 70px"
                        :preview-src-list="value.previewSrcList ? value.previewSrcList(scope.row, value) : value.getImgurl(scope.row, value).split(',')"/>
            </template>
            <template v-else>
              {{ scope.row[value.prop] }}
            </template>
          </template>
          <!--扩展dom-->
          <template v-else>
            <Table :key="`cus${index}`" :render="value.render" :param="scope.row"></Table>
          </template>
        </template>
      </el-table-column>
      <!--基础操作-->
      <el-table-column label="操作">
        <template slot-scope="scope">
          <el-button type="text" v-for="(value,index) in operator" @click="value.click(scope.row, value)" :key="index">
            {{ value.text }}
          </el-button>
        </template>
      </el-table-column>
    </el-table>
    <!--分页插件-->
    <el-pagination
      v-show="total>0"
      :total="total"
      :page-size.sync="pageSize"
      :current-page.sync="currentPage"
      :page-sizes="[10, 20, 30, 50]"
      layout="total, sizes, prev, pager, next, jumper"
      @current-change="handleCurrentChange"
      @size-change="handleSizeChange"
      v-bind="$attrs">
    </el-pagination>
  </div>
</template>

<script>
// render函数
import Table from './table'
export default {
  components: {Table},
  props: {
    tableTitle: {
      type: Object,
      default: {
        stripe: false,
        border: false,
        fit: true,
        highlightCurrentRow: false
      }
    },
    firstTableCol: {
      type: Object,
      default: {
        select: false,
        width: 55,
        type: 'selection'
      }
    },
    tableCol: {
      type: Array,
      default: []
    },
    tableData: {
      type: Array,
      default: []
    },
    operator: {
      type: Array,
      default: []
    },
    total: {
      type: Number,
      default: 0
    },
    page: {
      type: Number,
      default: 1
    },
    limit: {
      type: Number,
      default: 10
    },
    autoScroll: {
      type: Boolean,
      default: true
    }
  },
  computed: {
    currentPage: {
      get () {
        return this.page
      },
      set (val) {
        this.$emit('update:page', val)
      }
    },
    pageSize: {
      get () {
        return this.limit
      },
      set (val) {
        this.$emit('update:limit', val)
      }
    }
  },
  data () {
    return {
    }
  },
  methods: {
    // 监听table选择框
    handleSelectionChange (selection) {
      // 调用父组件对应的方法 handleSelectionChange
      this.$emit('handleSelectionChange', selection)
    },
    // 监听每页多少条数据(limit)
    handleSizeChange (limit) {
      this.$emit('pagination', {page: this.currentPage, limit: limit})
      if (this.autoScroll) {
        scrollTo(0, 800)
      }
    },
    // 监听当前是第几页(page)
    handleCurrentChange (page) {
      this.$emit('pagination', {page: page, limit: this.pageSize})
      if (this.autoScroll) {
        scrollTo(0, 800)
      }
    }
  }
}
</script>
<style scoped>
</style>

第二步:父组件与子组件进行render通信

为了实现父组件render函数在子组件中生效,我们需要定义一个render函数,在子组件中引用。

// table.js
export default {
  props: {
    render: {
      type: Function
    },
    param: {
      type: Object
    }
  },
  render(h) {
    return this.render(h, this.param)
  }
}

第三步:使用组件

<template>
  <div>
    <!--
        @自定义事件="父组件方法", 子组件中,this.$emit('自定义事件名称') 触发父组件事件。
        ref="proTable",标记在子组件上,指向子组件实例
    -->
    <proTable ref="proTable" :tableTitle="tableTitle" :tableCol="tableCol" :tableData="tableData" :operator="operator"
        :firstTableCol="firstTableCol"
        @handleSelectionChange="handleSelectionChange"
        :total="total" :page.sync="queryParams.page" :limit.sync="queryParams.limit" @pagination="getList"/>

  </div>
</template>

<script>
import proTable from './pro-table'

export default {
  components: {
    proTable
  },
  data() {
    return {
      queryParams: {
        page: 1,
        limit: 10,
      },
      type: 'success',
      total: 50,
      // element-ui中对table属性的设置
      tableTitle: {
        'stripe': true,
        "highlightCurrentRow": true
      },
      // 设置table的列
      tableCol: [
        { prop:'date',label:'日期'},
        { prop:'name',label:'姓名'},
        { prop:'address',label:'地址',width: 300},
        { prop:'src',label:'图片',  
        getImgurl: (row, col, cellValue) => { return this.getImgurl(row)}, 
        previewSrcList: (row, col, cellValue) => {return this.listImgUrl(row)}},
        { prop:'sex',label:'性别',  
        formatter: (row, col, cellVaule) => {return this.sexFormatter(row)}},
        { prop:'src',label:'图片',  
        getImgurl: (row, col, cellValue) => { return this.getImgurl(row)}},
        { prop:'text',label:'函数', render: (h, params) => {return  this.render(h, params)}}
      ],
      // table的基本操作
      operator: [
        {'text':'详情', click: (row, col, cellValue) => {return this.getInfo(row)}},
        {'text':'删除', click: (row, col, cellValue) => {return this.delInfo(row)}},
        {'text':'编辑', click: (row, col, cellValue) => {return this.editInfo(row)}},
      ],
      // 模拟数据
      tableData: [
        {
          date: '2016-05-02',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄',
          sex: 0,
          img:'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic2.zhimg.com%2F50%2Fv2-193cbb243dc14d3a016caaa54ba02837_hd.jpg&refer=http%3A%2F%2Fpic2.zhimg.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1628435704&t=deb5584cb9ff53fe6977f14a5e0755bb'
        }, {
          date: '2016-05-04',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1517 弄',
          sex: 1,
          img:'https://pic1.zhimg.com/80/v2-894ab624807fd4cfa33dd4e42cc90ac8_720w.jpg?source=1940ef5c'
        }, {
          date: '2016-05-01',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1519 弄',
          sex: 0,
          img:'xx.jpg'
        }, {
          date: '2016-05-03',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1516 弄',
          sex: 1,
          img:'xx.jpg'
        }],
      firstTableCol: {
        'select': true,
        'type': 'selection'
      }
    }
  },
  methods: {
    getInfo(val) {
      // 触发父方法
      console.log("获取详情",val)
    },
    delInfo(val) {
      // 触发父方法
      console.log("删除信息",val)
    },
    editInfo(val) {
      // 触发父方法
      console.log("编辑信息",val)
    },
    getImgurl(val) {
      console.log(val.img)
      return val.img
    },
    sexFormatter(val) {
      return val.sex === 0 ? '男' : '女'
    },
    handleSelectionChange(val) {
      console.log("监听选择框",val)
    },
    getList(queryParams) {
      console.log("父级方法",queryParams)
    },
    listImgUrl() {
      let array = [];
      array.push("https://pic1.zhimg.com/80/v2-894ab624807fd4cfa33dd4e42cc90ac8_720w.jpg?source=1940ef5c");
      array.push("https://cdn.pixabay.com/photo/2021/07/01/21/20/girl-6380331_960_720.jpg");
      return array;
    },
    render(h, params) {
      return h('span', null , '我是一个render组件')
    }
  }
}
</script>

总结

在引用组件的页面中,我们可以给每一个table列加方法,也可以给编辑、删除、详情添加自定义的方法,完全实现定制化。也可以自定义render函数。效果图如下:

上一篇:Vue中的Object.defineProperty全面理解

栏    目:vue

下一篇:详细聊聊Vue生命周期的那些事

本文标题:Vue封装通用table组件的完整步骤记录

本文地址:http://www.codeinn.net/misctech/205863.html

推荐教程

广告投放 | 联系我们 | 版权申明

重要申明:本站所有的文章、图片、评论等,均由网友发表或上传并维护或收集自网络,属个人行为,与本站立场无关。

如果侵犯了您的权利,请与我们联系,我们将在24小时内进行处理、任何非本站因素导致的法律后果,本站均不负任何责任。

联系QQ:914707363 | 邮箱:codeinn#126.com(#换成@)

Copyright © 2020 代码驿站 版权所有