关于vue.js:vueelement-动态表格组件

需要

1.表头数据不固定
2.表头数据多层级
3.表格跨行跨列
4.表格可编辑
5.编辑反对根本表单框

子组件代码

dynamic-header.vue

<template>
  <div>
    <el-form size="medium" class="horizontal" inline>
      <slot name="search"></slot>
    </el-form>
    <div class="title" v-if="title">{{title}}</div>
    <el-table
      v-loading="listLoading"
      :data="list"
      :stripe="true"
      class="flexible"
      :border="true"
      :span-method="arraySpanMethod"
      style="overflow: auto"
      :height="height"
      ref="table"
      width="100%"
    >
      <template
        v-for="(item,index) in tableHeader">
        <table-column  v-if="item.children && item.children.length" :key="Math.random()"  :coloumn-header="item"></table-column>
        <el-table-column v-else  class-name="custom"
                         :width="item.width?item.width:'auto'"
                         :fixed="item.fixed"
                         :key="Math.random()"
                         :label="item.tableHeadName"
                         align="center">
          <template slot-scope="scope">
            <template v-if="item.isEdit">
              <el-select
                filterable
                v-if='(item.htmlType == "select" || item.htmlType == "radio") && item.dictData'
                v-model.lazy="scope.row[item.tableFiled]">
                <el-option
                  v-for="dict in item.dictData"
                  :key="dict[item.options.value] || dict.value"
                  :label="dict[item.options.label] || dict.label"
                  :value="parseInt(dict[item.options.value] || dict.value)"
                />
              </el-select>

              <el-date-picker
                v-else-if='item.htmlType == "datetime" && item.queryType != "BETWEEN"' clearable size="small"
                v-model.lazy="scope.row[item.tableFiled]"
                type="date"
                value-format="yyyy-MM-dd">
              </el-date-picker>
              <el-date-picker
                v-else-if='item.htmlType == "datetime" && item.queryType == "BETWEEN"'
                v-model.lazy="scope.row[item.tableFiled]"
                size="small"
                style="width: 240px"
                value-format="yyyy-MM-dd"
                type="daterange"
                range-separator="-"
                start-placeholder="开始日期"
                end-placeholder="完结日期"
              ></el-date-picker>
              <el-input-number
                v-else-if='item.htmlType == "number"'
                v-model.lazy="scope.row[item.tableFiled]"
                clearable
                size="small"
              />
              <el-input
                v-else
                v-model.lazy="scope.row[item.tableFiled]"
                clearable
                size="small"
              />
            </template>
            <template v-else-if="item.template">
              {{getTemplate(item.template,scope)}}
            </template>
            <template v-else>
              <dict-tag v-if="item.dictData" :options="item.dictData" :value="scope.row[item.tableFiled]" />
              <tempalte  v-else-if="item.dictDataArray" >
                <dict-tag v-for="(it,itIndex) in item.dictDataArray"  v-if="scope.row[it.props] == it.value" :key="itIndex" :options="it.dictData" :value="scope.row[item.tableFiled]" />
              </tempalte>
              <template v-else>{{scope.row[item.tableFiled]}}</template>
            </template>
          </template>
        </el-table-column>
      </template>
      <el-table-column v-if="pageParamInfo.oper" label="操作" :key="index" fixed="right" width="150">
        <template slot-scope="scope">
          <slot name="oper" :scope="scope.row"></slot>
        </template>
      </el-table-column>
    </el-table>
    <slot name="tableFooter" :scope="pageParamInfo.req"></slot>
  </div>

</template>
<script>
  import TableColumn from './table-column'
  export default {
    props: {
      pageParamInfo: {
        type: Object,
        default(){
          return {}
        }
      },
      tableHeader: {
        type: Array,
        default(){
          return []
        }
      },
      RowRules: {
        type: Array,
        default(){
          return []
        }
      },
      list: {
        type: Object,
        default(){
          return {}
        }
      },
      title: {
        type: String,
        default: ""
      },
      listLoading: {
        type: Boolean,
        default:  false
      },
      height: {
        type: String,
        default: "70vh"
      },
    },
    // pageParamInfo 页面列表参数:url  req等等;
    // tableHeader 表头信息
    components: {
      TableColumn,
    },
    data() {
      return {
      }
    },
    watch: {
      tableHeight(val) {
        this.height = val
      }
    },
    created() {
    },
    mounted() {
    },
    methods: {
      getTemplate(template,scope){
        return eval(template)
      },
      arraySpanMethod({ row, column, rowIndex, columnIndex }) {
        let returnMap = {
          rowspan: 1,
          colspan: 1
        }
        const data = this.RowRules
        if (data instanceof Array && data.length > 0) {
          data.forEach(item => {
            if (item.col === (columnIndex + 1)) {
              if (rowIndex % item.row === 0) {
                returnMap = {
                  rowspan: item.row,
                  colspan: 1
                }
              } else {
                returnMap = {
                  rowspan: 0,
                  colspan: 0
                }
              }
            }
          })
        }
        return returnMap
      },
      // 列表
      getList() {
        this.listLoading = true
        this.$http.post(this.pageParamInfo.url, this.pageParamInfo.req).then(res => {
          this.listLoading = false
          // this.list = res.data.list
        })
      },
      // 文件上传中解决
      handleExceed(event, file, fileList) {
        this.upload.isUploading = true
      },
      // 文件上传胜利解决
      handleSuccess(response, file, fileList) {
        this.upload.open = false
        this.upload.isUploading = false
        this.$refs.upload.clearFiles()
        this.$alert(response.message, '导入后果', {
          dangerouslyUseHTMLString: true,
        })
        this.getList()
      },
      // 重置
      reset() {
        /* this.listLoading = true
         this.$http.post('busprojecttask/findTaskList', this.req).then(res => {
           this.listLoading = false
            this.getList(this.req.MONTH)
         })*/
      },
      // 批改
      save() {
        /* this.listLoading = true
          this.$http.post('busprojecttask/findTaskList', this.req).then(res => {
            this.listLoading = false
             this.getList(this.req.MONTH)
          })*/
      }
    }
  }
</script>

<style  lang="scss" scoped>
  h1{
    color: black !important;
    text-align: center;
    padding: 20px;
  }
  table{
    margin-top: 20px;
  }
  .tableClass{
    ::v-deep .el-table__fixed{
      height: 100% !important;   //设置高优先,以笼罩内联款式
    }
  }
</style>

table-column.vue

<template>
  <el-table-column :label="coloumnHeader.tableHeadName" :prop="coloumnHeader.tableFiled" align="center">
    <template v-for="item in coloumnHeader.children">
      <tableColumn v-if="item.children && item.children.length" :key="Math.random()"  :coloumn-header="item"></tableColumn>
      <el-table-column :fixed="item.fixed" :width="item.width?item.width:'auto'"  v-else :key="Math.random()"  :label="item.tableHeadName" :prop="item.tableFiled" align="center">
        <template slot-scope="scope">
          <template v-if="item.isEdit">
            <el-select
              v-if='(item.htmlType == "select" || item.htmlType == "radio") && item.dictData'
              v-model.lazy="scope.row[item.tableFiled]">
              <el-option
                v-for="dict in item.dictData"
                :key="dict.value"
                :label="dict.label"
                :value="parseInt(dict.value)"
              />
            </el-select>
            <el-date-picker
              v-else-if='item.htmlType == "datetime" && item.queryType != "BETWEEN"' clearable size="small"
              v-model.lazy="scope.row[item.tableFiled]"
              type="date"
              value-format="yyyy-MM-dd">
            </el-date-picker>
            <el-date-picker
              v-else-if='item.htmlType == "datetime" && item.queryType == "BETWEEN"'
              v-model.lazy="scope.row[item.tableFiled]"
              size="small"
              style="width: 240px"
              value-format="yyyy-MM-dd"
              type="daterange"
              range-separator="-"
              start-placeholder="开始日期"
              end-placeholder="完结日期"
            ></el-date-picker>
            <el-input-number
              v-else-if='item.htmlType == "number"'
              v-model.lazy="scope.row[item.tableFiled]"
              clearable
              size="small"
            />
            <el-input
              v-else
              v-model.lazy="scope.row[item.tableFiled]"
              clearable
              size="small"
            />
          </template>
          <template v-else-if="item.template">
            {{getTemplate(item.template,scope)}}
          </template>
          <template v-else>
            <dict-tag v-if="item.dictData" :options="item.dictData" :value="scope.row[item.tableFiled]" />
            <tempalte  v-else-if="item.dictDataArray" >
              <dict-tag v-for="(it,itIndex) in item.dictDataArray"  v-if="scope.row[it.props] == it.value" :key="itIndex" :options="it.dictData" :value="scope.row[item.tableFiled]" />
            </tempalte>
            <template v-else>{{scope.row[item.tableFiled]}}</template>
          </template>
        </template>
      </el-table-column>
    </template>
  </el-table-column>
</template>

<script>
export default {
  name: 'TableColumn',
  props: {
    coloumnHeader: {
      type: Object,
      required: true
    }
  }
}
</script>

<style scoped>

</style>

父组件

list为表格数据,tableHeader为表头数据

<template>
  <dynamicHeaderEdit
            :tableHeader="tableHeader"
            :list="list"
            ref="table">
          </dynamicHeaderEdit>
</template>

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理