封装element-ui动态表格组件(带图片)

233 阅读1分钟

实现效果:

image.png

封装组件:

<template>
  <div class="app-container">
    <el-table
      ref="multipleTable"
      :data="data"
      tooltip-effect="dark"
      style="width: 100%"
      :fit="tableAttribute.fit"
      :border="tableAttribute.border"
      :size="tableAttribute.size"
      :highlight-current-row="tableAttribute.highlightCurrentRow"
      @selection-change="handleSelectionChange"
    >
      <el-table-column
        :type="TableSelect.type"
        :width="TableSelect.width"
        v-if="TableSelect.select"
      >
      </el-table-column>
      <el-table-column
        v-for="(item,index) in tableHeader"
        :key="index"
        :prop="item.prop"
        :label="item.label"
        :width="item.width"
        :align="item.align"
        :show-overflow-tooltip="true"
      >
        <template slot-scope="scope">
          <!-- 渲染没有 dataType 属性和 render 函数的表头数据-->
          <!-- 连载时间等 -->
          <template v-if="!item.dataType && !item.render">
            {{ scope.row[item.prop]}}
          </template>
          <!-- 渲染图片 -->
          <template v-if="item.dataType && item.dataType=='img'">
            <el-image
              lazy
              :src="item.render(data[scope.$index][item.prop],scope.row)"
              style="width: 70px; height: 70px"
              :preview-src-list="preview(data[scope.$index][item.prop])"
            />
          </template>
          <!-- 渲染有 render 属性表头数据,例如性别-->
          <template v-if="item.render && !item.dataType">
            {{ item.render(data[scope.$index][item.prop],scope.row)}}
          </template>
        </template>
      </el-table-column>
      <slot></slot>
    </el-table>
    <!-- 分页 -->
    <el-pagination
      :total="total"
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
      :current-page="currentPage"
      :page-sizes="[5, 10, 20, 30, 40]"
      :page-size="pageSize"
      layout="total, sizes, prev, pager, next, jumper"
    >
    </el-pagination>
  </div>
</template>

<script>
export default {
  props: {
    render: {
      type: Function,
    },
    param: {
      type: Object,
    },
    // 表格属性
    tableAttribute: {
      type: Object,
      default: () => {},
      required: true
    },
    // 表格数据
    data: {
      type: Array,
      default: () => [],
      required: true
    },
    // 表头数据
    tableHeader: {
      type: Array,
      default: () => [],
      required: true
    },
    // 表格选择框
    TableSelect: {
      type: Object,
      default: () => {},
      required: true
    },
    // 分页数据数量总数
    total: {
      type: Number,
      default: 20,
    },
    // 分页当前页
    page: {
      type: Number,
      default: 1,
    },
    // 分页每页显示多少条数据
    limit: {
      type: Number,
      default: 10,
    },
  },
  //为了实现父组件render函数在子组件中生效,我们需要定义一个render函数,在子组件中引用
  render(h) {
    return this.render(h, this.param)
  },
  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)
      },
    },
  },
  methods: {
    // 选中表格选择框
    handleSelectionChange(val) {
      console.log('选中的值:', val)
    },
    // 监听每页多少条数据(limit)
    handleSizeChange(limit) {
      this.$emit('pagination', { page: this.currentPage, limit: limit })
    },
    // 监听当前是第几页(page)
    handleCurrentChange(page) {
      this.$emit('pagination', { page: page, limit: this.pageSize })
    },
    // 预览图片
    preview(val) {
      let arr = []
      arr.push(val)
      return arr
    },
  },
}
</script>

<style scoped>
.app-container {
  margin: 100px auto;
}
.btn {
  display: flex;
  justify-content: flex-end;
  margin: 0 40px 20px 0;
}
.el-pagination {
  text-align: center;
  margin-top: 40px;
}
</style>

引用组件:

<template>
  <div>
    <dynamic-table
      :total="total"
      :data="tableData"
      :TableSelect="TableSelect"
      :tableHeader="tableHeader"
      :tableAttribute="tableAttribute"
      :page.sync="queryParams.page"
      :limit.sync="queryParams.limit"
      @pagination="getList"
    >
      <template>
        <el-table-column
          label="操作"
          style="width:120px;"
        >
          <template slot-scope="scope">
            <el-button
              type="text"
              @click="viewClick(scope.row)"
            >查看</el-button>
            <el-button
              type="text"
              @click="editClick(scope.row)"
            >编辑</el-button>
          </template>
        </el-table-column>
      </template>
    </dynamic-table>
  </div>
</template>

<script>
import DynamicTable from './DynamicTable.vue'
import axios from 'axios'
export default {
  components: {
    DynamicTable,
  },
  data() {
    return {
      queryParams: {
        page: 1, //当前页
        limit: 10, //每页显示多少条
      },
      total: 20, //数据总条数
      // 表格属性
      tableAttribute: {
        stripe: true,
        border: true,
        fit: true,
        highlightCurrentRow: true, //是否显示选中当前行高亮
        size: 'small',
        align:'center'
      },
      // 表头
      tableHeader: [
        { prop: 'serialTime', label: '连载时间', align: 'center' },
        { prop: 'endTime', label: '完结时间', align: 'left' },
        { prop: 'novel', label: '小说名', align: 'left' },
        { prop: 'protagonist', label: '主角', align: 'center' },
        {
          prop: 'sex',
          label: '性别',
          render: (text, row) => {
            return row.sex == true ? '男' : '女'
          },
          align: 'center'
        },
        { prop: 'serialPlatform', label: '连载平台' },
        { prop: 'totalWords', label: '总字数(万)',align: 'right' },
        {
          prop: 'img',
          label: '图片',
          dataType: 'img',
          render: (text, row) => {
            if (row.echoMap) {
              return row.echoMap.img.src
            } else {
              return row.img
            }
          },
          align: 'center'
        },
        {
          prop: 'dec',
          label: '描述',
          previewDec: (row, col, cellValue) => {
            return row
          },
        },
      ],
      //表格数据
      tableData: [],
      // 表格选择框
      TableSelect: {
        select: true,
        type: 'selection',
        width: 60,
        align:'center'
      },
    }
  },
  mounted() {
    
    this.getData()
  },

  methods: {
    render(h, params) {
      return h('span', null, '我是一个render组件')
    },
    // 获取总数据条数
    getList() {
      this.total = this.tableData.length
    },
    viewClick(val) {
      console.log('查看', val)
    },
    editClick(val) {
      console.log('编辑', val)
    },
    getData(){
       axios.post("http://localhost:8080/goods/goodAll").then((res)=>{
            console.log(res.data.data)
            this.tableData=res.data.data
            this.getList()
        })
    },
  },
}
</script>

<style>
</style>

mock.js:

const Mock = require('mockjs')
let Random = Mock.Random
let data = Mock.mock({
  "data|10": [// 生成10条数据
    {
      "novelId|+1": 1,//生成小说id,自增1
      "serialTime": '@date',//模拟连载时间
      "endTime": '@date',//模拟完结时间
      "novel": '《' + Random.cword(4, 7) + '》',//小说名
      "protagonist": Random.cname(),//主角名
      "sex|1-2": true,//性别
      'serialPlatform': Random.cword(4, 6),//连载平台
      "totalWords|500-700": 1,//小说字数总数
      "img": Random.image('400x600', '#894FC4'),//小说动漫封面
      "dec": Random.cparagraph(30, 60),//描述
    }
  ]
})

Mock.mock(/goods\/goodAll/, 'post', () => { //三个参数。第一个:路径,第二个:请求方式post/get,第三个:回调,返回值
  return data
})

安装axios库,并在main.js中将axios挂载到vue实例中:

import axios from 'axios';
Vue.prototype.$http = axios;