vue2 基于element Table表格二次封装 快速CRUD

223 阅读2分钟

对于中后台管理系统,每个页面的Table数据结构基本相似。 所以对Table简单封装,便于快速开发。主打一个CRUD

gitee 获取

gitee.com/moderationz…

微信图片_20230609202841.png

首先工具区

 // 表格有操作列时设置
        operation: {
          isOperation: true, // 是否显示操作
          label: '操作666', // 列名
          width: '', // 根据实际情况给宽度
          align: 'left/center/right', //  每一列的对齐方式
          data: [ // 功能数组
            {
              type: 'info', //按钮类型icon为图表类型
              label: '推荐', // 功能
              icon: 'el-icon-search',
              size: 'small', // 按钮大小
              plain: false, //  是否设置朴素类型
              round: false, //  是否圆角按钮
              circle: false, // 是否设置为圆形
              permission: '3010105', // 后期这个操作的权限,用来控制权限
              handleRow: this.handleRow  //方法
            },
            {
              type: 'success', // 按钮类型icon为图表类型
              label: '', // 功能
              icon: 'el-icon-search',
              size: 'small', // 按钮大小
              plain: false, //  是否设置朴素类型
              round: false, //  是否圆角按钮
              circle: false, // 是否设置为圆形
              permission: '3010105', // 后期这个操作的权限,用来控制权限
              handleRow: this.handleRow  // 方法
            }
          ]
        },

数据渲染区

 index: true, //  表格 序列  1、2、3 是否开启
        data: [], //  table数据
        // 可直接渲染的数据
        thead: [
          // label:头部标签    
          // prop:绑定数据属性名  
          // width:自定义宽度  
          // align:left/center/right 对齐方式
          // isImage: false, 是否开启自定义图片插槽
          { label: '广告图', prop: 'advpossize', width: '', align: 'left/center/right', isImage: false, },
          { label: '广告位名称', prop: 'advposname', width: '' },
          { label: '广告图描述', prop: 'advposdesc', width: '' },
          { label: '广告图数量', prop: 'advposnum', width: '' },
 
          // { label: '图片', prop: 'advposn', width: '', isImage: false ,},
          // { label: '开关', prop: 'advposn', width: '', isSwitch: false },
          // { label: '标签', prop: 'advposn', width: '', isImage: false ,},
        ],

按钮删除编辑  操作区域

 // 表格有操作列时设置
        operation: {
          isOperation: true, // 是否显示操作
          label: '操作666', // 列名
          width: '', // 根据实际情况给宽度
          align: 'left/center/right', //  每一列的对齐方式
          data: [ // 功能数组
            {
              type: 'info', //按钮类型icon为图表类型
              label: '推荐', // 功能
              icon: 'el-icon-search',
              size: 'small', // 按钮大小
              plain: false, //  是否设置朴素类型
              round: false, //  是否圆角按钮
              circle: false, // 是否设置为圆形
              permission: '3010105', // 后期这个操作的权限,用来控制权限
              handleRow: this.handleRow  //方法
            },
            {
              type: 'success', // 按钮类型icon为图表类型
              label: '', // 功能
              icon: 'el-icon-search',
              size: 'small', // 按钮大小
              plain: false, //  是否设置朴素类型
              round: false, //  是否圆角按钮
              circle: false, // 是否设置为圆形
              permission: '3010105', // 后期这个操作的权限,用来控制权限
              handleRow: this.handleRow  // 方法
            }
          ]
        },

分页器

 // 分页器
        pageData: {
          total: 0, // 总条数
          limit: 4, // 每页数量
          page: 1, // 页码,
          pageSizes: [4, 10, 20, 50]
        }

以上是配置

下面是组件的封装

<template>
  <div class="content-box">
    <!-- 工具区 -->
    <el-row justify="space-between" v-if="config.tool.length">
      <div></div>
      <!-- 有权限后使用    v-permission="item.permission" -->
      <div>
        <template v-for="item in config.tool">
          <el-button v-bind="item" v-if="item.isAddBtn">
            {{ item.name }}
          </el-button>
 
          <el-button v-bind="item" v-if="!item.isAddBtn">
            {{ item.name }}
          </el-button>
        </template>
      </div>
    </el-row>
 
    <div class="table">
      <el-table border :data="config.data">
        <!-- 序列 -->
        <el-table-column v-if="config.index" type="index" label="#" />
        <template v-for="item in config.thead">
          <!-- 自己定义   比如要输入框 显示图片等等 自己定义-->
          <el-table-column v-if="item.isImage" :key="item.prop" v-bind="item">
            <template slot-scope="scope">
              <slot :name="item.prop" :scope="scope">
                <el-image style="width: 100px; height: 100px" :src="url" :fit="fit"></el-image>
              </slot>
            </template>
          </el-table-column>
          <!-- 自己定义   比如要输入框 显示图片等等 自己定义-->
          <el-table-column v-if="item.isSwitch" :key="item.prop" v-bind="item">
            <template slot-scope="scope">
              <slot :name="item.prop" :scope="scope">
                <el-switch v-model="value" active-color="#13ce66" inactive-color="#ff4949" active-value="100"
                  inactive-value="0">
                </el-switch>
              </slot>
            </template>
          </el-table-column>
 
          <el-table-column v-if="item.isTag" :key="item.prop" v-bind="item">
            <template slot-scope="scope">
              <slot :name="item.prop" :scope="scope">
                <el-tag type="success">标签二</el-tag>
              </slot>
            </template>
          </el-table-column>
 
          <!-- 大部分适用 可直接渲染-->
          <el-table-column v-if="!item.isImage && !item.isSwitch && !item.isTag" :key="item.prop" v-bind="item"
            show-overflow-tooltip />
        </template>
 
        <!-- 操作部分 -->
        <el-table-column v-if="config.operation.isOperation" v-bind="config.operation">
          <template slot-scope="scope">
            {{ scope }}
            <el-button v-for="item, index in config.operation.data" :key="index" v-bind="item"
              @click.native.prevent="item.handleRow(scope.$index, scope.row, item.label)">{{ item.label }}</el-button>
          </template>
 
          <template v-if="item.type !== 'icon'" slot-scope="scope">
            <el-button v-permission="item.permission" v-bind="item" :type="item.type ? item.type : ''" size="mini"
              @click.native.prevent="item.handleRow(scope.$index, scope.row, item.label)">
              {{ item.label }}
            </el-button>
          </template>
          <template v-else>
            <i :class="[icon, item.icon]" v-bind="item" @click="item.handleRow(scope.$index, scope.row, item.label)" />
          </template>
        </el-table-column>
 
 
 
        <!-- 操作部分二   如果出问题就用一-->
        <el-table-column v-if="config.operation.isOperation" v-bind="config.operation">
          <!-- UI统一一排放3个,4个以上出现更多 -->
          <template slot-scope="scope">
            <!-- 三个一排的情况,去掉隐藏的按钮后的长度 -->
            <template v-if="config.operation.data.length > 0">
              <div class="btn">
                <div v-for="(item, index) in config.operation.data" :key="index">
                  <template v-if="item.type !== 'icon'">
                    <el-button v-permission="item.permission" v-bind="item" :type="item.type ? item.type : ''"
                      @click.native.prevent="item.handleRow(scope.$index, scope.row, item.label)">
                      {{ item.label }}
                    </el-button>
                  </template>
                  <template v-else>
                    <i :class="[icon, item.icon]" v-bind="item"
                      @click="item.handleRow(scope.$index, scope.row, item.label)" />
                  </template>
                </div>
              </div>
            </template>
          </template>
        </el-table-column>
      </el-table>
    </div>
 
    <!--分页区域-->
    <div class="pagination">
      <el-pagination :current-page.sync="config.pageData.page" :page-sizes="config.pageData.pageSizes"
        :page-size="config.pageData.limit" layout="total, sizes, prev, pager, next, jumper" :total="config.pageData.total"
        background @size-change="handleSizeChange" @current-change="handleCurrentChange" />
    </div>
  </div>
</template>
<script>
export default {
  name: 'TableConfig',
  props: {
    config: {
      type: Object,
      default: () => { }
    }
  },
  // 监听数据
  watch: {
    config: {
      handler(newVal) {
      },
      deep: true,
      immediate: true
    }
  },
  methods: {
    handleSizeChange(val) {
      this.$emit('changeSize', val)
      console.log(`每页 ${val} 条`)
    },
    handleCurrentChange(val) {
      this.$emit('changeNum', val)
      console.log(`当前页: ${val}`)
    }
  }
}
</script>
 
<style lang="scss" scoped>
.content-box {
  padding: 20px 30px;
}
 
.table {
  padding-top: 10px;
}
 
.pagination {
  margin-top: 10px;
}
</style>

所有配置

<template>
  <div id="app">
    <TableConfig :config="tableConfig" @changeSize="changeSize" @changeNum="changeNum" />
  </div>
</template>
 
<script>
import TableConfig from './components/table.vue'
 
export default {
  name: 'App',
  components: {
    TableConfig
  },
  data() {
    return {
      // table配置
      tableConfig: {
        //  工具区   
        tool: [
          //按钮名称  唯一标识符 权限点 使用element自带按钮类型  自定义背景色
          { name: '新增', key: 1, permission: '', type: 'primary', bgColor: '', isAddBtn: true },
          // { name: '新增用户', key: 1, permission: '', type: 'primary', bgColor: '', },
        ],
        index: true, //  表格 序列  1、2、3 是否开启
        data: [], //  table数据
        // 可直接渲染的数据
        thead: [
          // label:头部标签    
          // prop:绑定数据属性名  
          // width:自定义宽度  
          // align:left/center/right 对齐方式
          // isImage: false, 是否开启自定义图片插槽
          { label: '广告图', prop: 'advpossize', width: '', align: 'left/center/right', isImage: false, },
          { label: '广告位名称', prop: 'advposname', width: '' },
          { label: '广告图描述', prop: 'advposdesc', width: '' },
          { label: '广告图数量', prop: 'advposnum', width: '' },
 
          // { label: '图片', prop: 'advposn', width: '', isImage: false ,},
          // { label: '开关', prop: 'advposn', width: '', isSwitch: false },
          // { label: '标签', prop: 'advposn', width: '', isImage: false ,},
        ],
 
        // 表格有操作列时设置
        operation: {
          isOperation: true, // 是否显示操作
          label: '操作666', // 列名
          width: '', // 根据实际情况给宽度
          align: 'left/center/right', //  每一列的对齐方式
          data: [ // 功能数组
            {
              type: 'info', //按钮类型icon为图表类型
              label: '推荐', // 功能
              icon: 'el-icon-search',
              size: 'small', // 按钮大小
              plain: false, //  是否设置朴素类型
              round: false, //  是否圆角按钮
              circle: false, // 是否设置为圆形
              permission: '3010105', // 后期这个操作的权限,用来控制权限
              handleRow: this.handleRow  //方法
            },
            {
              type: 'success', // 按钮类型icon为图表类型
              label: '', // 功能
              icon: 'el-icon-search',
              size: 'small', // 按钮大小
              plain: false, //  是否设置朴素类型
              round: false, //  是否圆角按钮
              circle: false, // 是否设置为圆形
              permission: '3010105', // 后期这个操作的权限,用来控制权限
              handleRow: this.handleRow  // 方法
            }
          ]
        },
 
        // 分页器
        pageData: {
          total: 0, // 总条数
          limit: 4, // 每页数量
          page: 1, // 页码,
          pageSizes: [4, 10, 20, 50]
        }
      },
    }
  },
  methods: {
    // 编辑或删除  
    handleRow(index, row, item) {
      console.log(index, row, item);
    },
 
    //  删除   并处理边缘问题
    async delRow(id) {
      await removeCateApi({ id })
      this.$message.success('删除成功')
      // bug  优化   最后页面删除  不出数据
      if (this.queryData.page > 1 && this.tableConfig.data.length === 1) {
        this.queryData.page--
      }
      this.initData()
    },
 
    // 改变每页数量
    changeSize(size) {
      this.tableConfig.pageData.limit = size
      this.getList()
    },
    // 改变页码
    changeNum(pageNum) {
      this.tableConfig.pageData.page = pageNum
      this.getList()
    },
  },
}
</script>
 
<style></style>

更多功能请看 [juejin.cn/post/695156…](url)