表格封裝:讓咱們輕鬆的coding~

表格複用

在後端管理項目中,咱們一般有着許多重複利用的組件,尤爲是表格與分頁器是用得最多的。咱們採用的是 element-ui因此咱們對其進行了封裝。javascript

封裝組件

com-list.vuecss

<template>
  <section class="com-list">

    <el-table v-loading="loading" :data="sourceData" @selection-change="selectionChange" class="com-list__table">

      <!-- 選擇框 -->
      <el-table-column v-if="selectVisible" type="selection" width="45" align="center" />

      <!-- 主體數據 -->
      <template v-for="(column, idx) in columns">
        <el-table-column v-if="column.prop" :key="idx" :prop="column.prop" :label="column.label" :formatter="column.formatter" :sortable="column.sortable" :align="column.align" :width="column.width">
        </el-table-column>
        <slot v-else-if="column.slot" :name="column.slot" />
      </template>

      <!-- 分頁 -->
      <div v-if="needPage" class="com-list__footer" slot="append">
        <el-row type="flex" justify="left">
          <el-col>
            <el-button v-if="deleteVisible" type="danger" size="small">批量刪除</el-button>
            <el-button v-if="setGroupVisible" size="small">設置分組</el-button>
            <slot name="read" />
          </el-col>
          <el-col class="pagination" v-if="needPage" :span="6">
            <el-pagination small background layout="prev, pager, next" :total="pageTotal" :page-size="pageRequest.limit" :current-page.sync="pageRequest.page" @current-change="page => $emit('pageChange', page)" @size-change="size => $emit('pageChange', size)" >
            </el-pagination>
          </el-col>
        </el-row>
      </div>
    </el-table>

  </section>
</template>

<script lang="ts"> import { Component, Vue, Prop } from 'vue-property-decorator' @Component export default class ComList extends Vue { @Prop({default: false}) loading!: boolean @Prop() sourceData!: any // 表格數據 @Prop() columns!: Array<object> // 表格項 @Prop({default: false}) selectVisible?: boolean // 選擇框 @Prop({default: false}) deleteVisible?: boolean // 批量刪除 @Prop({default: false}) setGroupVisible?: boolean // 設置分組 @Prop({default: true}) needPage?: boolean // 是否有分頁 @Prop({default: () => {return {page: 1, limit: 10, total: 0} }}) pageRequest?: object // 分頁數據 @Prop({default: 0}) pageTotal?: number // 分頁總數 private selections: Array<object> = [] private selectionChange(selections: Array<object>) { this.selections = selections this.$emit('selectionChange', { selections }) } } </script>

<style lang="scss" scoped> .com-list { ::v-deep &__table { border: 1px solid #EBF3FA; thead { font-size: 14px; color: #333; th { height: 70px; background: #EBF3FA; } } thead th, tbody, td { &:first-child:not(.el-table-column--selection) { .cell { padding-left: 36px; } } } } &__footer { margin: 22px; text-align: left; .pagination { margin-top: 6px; text-align: right; } .el-pagination { text-align: right; padding: 0; } } } </style>
複製代碼

其中的slot是很關鍵的一點,它能讓咱們自定義每一項,其餘的倒無非是增長相關屬性而已。html

使用組件

<com-list :source-data="tableData" :columns="columns" :selectVisible="true" :page-request="listQuery" :page-total="total" :loading="listLoading" :page-sizes="[10, 25, 50]" @pageChange="pageChange" @sizeChange="sizeChange" @selectionChange="selectionChange" >
      <template #status>
        <el-table-column label="狀態">
          <template slot-scope="scope">
            <el-tag :type="scope.row.status === 1 ? 'success' : 'danger'">
              {{scope.row.status === 1 ? '已處理' : '待處理'}}
            </el-tag>
          </template>
        </el-table-column>
      </template>
      <template #operation>
        <el-table-column label="操做">
          <template slot-scope="scope">
            <el-button type="text" size="small" @click="onLock(scope.row.cate_id)">查看</el-button>
          </template>
        </el-table-column>
      </template>
      <template #read>
        <el-button size="small" @click="setRead">標記已讀</el-button>
      </template>
</com-list>

<script lang="ts"> import { Component, Vue } from 'vue-property-decorator' import ComList from '@/components/ComList/index.vue' import Page from '@/mixins/pageMixins' @Component({ components: { ComList } }) export default class Message extends Page { public fetchList = this.$api.Message.getList private columns: Array<object> = [ { label: 'ID', prop: 'id' }, { label: '消息標題', prop: 'title' }, { slot: 'status' }, { label: '時間', prop: 'create_time' }, { slot: 'operation' } ] private selections: Array<object> = [] private selectionChange (parmars: any) { const arr: Array<object> = [] parmars.selections.forEach((el: any) => { arr.push(el.cate_id) }) this.selections = arr } } </script>
複製代碼

須要注意的是,咱們在其中引入了一個minxins它能讓咱們將一些屬性以及方法抽離出來,達到複用的目的。在vue-property-decorator中咱們使用的是 extends來繼承 mixinsvue

抽取可複用的方法以及屬性

mixins/pageMinxis.tsjava

import { Component, Vue, Watch } from 'vue-property-decorator'

@Component
export default class Page extends Vue {
  // 頁碼及每頁條數
  listQuery = {
    page: 1,
    limit: 10
  }
  total = 0
  listLoading = false // 是否加載中
  fetchList: any = null // 請求接口函數
  tableData = [] // 獲取數據
  searchForm = {} // 篩選條件

  @Watch('listQuery', { immediate: true, deep: true })
  listQueryChange () {
    this.getList()
  }

  // 頁碼切換
  pageChange(page: number) {
    this.listQuery.page = page
  }
  // 每頁條數切換
  sizeChange(size: number) {
    this.listQuery.limit = size
  }

  // 獲取列表數據
  async getList() {
    if (!this.fetchList || typeof this.fetchList !== 'function') {
      this.$message.error('請把列表接口函數賦值給fetchList')
      return
    }
    this.listLoading = true
    const query = this.$filterEmptyValue(this.listQuery, this.searchForm)
    const RESULT = await this.fetchList(query)
    if (RESULT.code === 1) {
      this.tableData = RESULT.data.data
      this.total = RESULT.data.total
      this.listLoading = false
    }
  }

  /** * @description: 操做項目及回調 * fn: 須要執行的函數 * cb: 回調(可傳空) * ...rest: 須要執行函數的參數 */
  async mixinHandleItem(fn: Function, cb: Function, ...rest: any) {
    const { code, data } = await fn(...rest)
    if (code === 1) {
      this.$message.success('操做成功')
      if (cb && typeof cb === 'function') {
        cb()
      }
    } else {
      this.$message.error(data || '操做失敗,請重試')
    }
  }
}
複製代碼

咱們能夠複用方法以及覆蓋屬性,便可高效利用代碼typescript

對以上代碼的優化

components/ComList.vueelement-ui

<template>
  <section class="com-list">

    <el-table v-loading="loading" :data="sourceData" @selection-change="selectionChange" class="com-list__table">

      <!-- 選擇框 -->
      <el-table-column v-if="selectVisible" type="selection" width="45" align="center" />

      <!-- 主體數據 -->
      <template v-for="(column, index) in columns">
        <el-table-column v-if="column.render" :key="column.prop" :label="column.label" >
          <template slot-scope="scope">
            <Render :row="scope.row" :index="index" :render="column.render" />
          </template>
        </el-table-column>
        <slot v-else-if="column.slot" :name="column.slot" />
        <el-table-column v-else :key="column.prop" v-bind="setAttrs(column)" />
      </template>

      <!-- 分頁 -->
      <div v-if="needPage" class="com-list__footer" slot="append">
        <el-row type="flex" justify="left">
          <el-col>
            <el-button v-if="deleteVisible" type="danger" size="small">批量刪除</el-button>
            <el-button v-if="setGroupVisible" size="small">設置分組</el-button>
            <slot name="read" />
          </el-col>
          <el-col class="pagination" v-if="needPage" :span="6">
            <el-pagination small background layout="prev, pager, next" :total="pageTotal" :page-size="pageRequest.limit" :current-page.sync="pageRequest.page" @current-change="page => $emit('pageChange', page)" @size-change="size => $emit('pageChange', size)" >
            </el-pagination>
          </el-col>
        </el-row>
      </div>
    </el-table>

  </section>
</template>

<script lang="ts"> import { Component, Vue, Prop } from 'vue-property-decorator' import Render from './render' @Component({ components: { Render } }) export default class ComList extends Vue { @Prop({default: false}) loading!: boolean @Prop() sourceData!: object // 表格數據 @Prop() columns!: Array<object> // 表格項 @Prop({default: false}) selectVisible?: boolean // 選擇框 @Prop({default: false}) deleteVisible?: boolean // 批量刪除 @Prop({default: false}) setGroupVisible?: boolean // 設置分組 @Prop({default: true}) needPage?: boolean // 是否有分頁 @Prop({default: () => {return {page: 1, limit: 10, total: 0} }}) pageRequest?: object // 分頁數據 @Prop({default: 0}) pageTotal?: number // 分頁總數 private selections: Array<object> = [] private selectionChange(selections: Array<object>) { this.selections = selections this.$emit('selectionChange', { selections }) } private setAttrs (params: object) { // eslint-disable-next-line const { slot, ...options }: any = params // 排除 slot return { ...options } } } </script>

<style lang="scss" scoped> .com-list { ::v-deep &__table { border: 1px solid #EBF3FA; thead { font-size: 14px; color: #333; th { height: 70px; background: #EBF3FA; } } thead th, tbody, td { &:first-child:not(.el-table-column--selection) { .cell { padding-left: 36px; } } } } &__footer { margin: 22px; text-align: left; .pagination { margin-top: 6px; text-align: right; } .el-pagination { text-align: right; padding: 0; } } } </style>
複製代碼

components/render.ts後端

import { CreateElement, RenderContext } from 'vue/types/umd'

export default {
  functional: true, props: {
    row: Object,
    render: Function,
    index: Number,
    column: {
      type: Object,
      default: null
    }
  },
  render: (h: CreateElement, ctx: RenderContext) => {
    const params: any = {
      row: ctx.props.row,
      index: ctx.props.index
    }
    if (ctx.props.column) params.column = ctx.props.column
    return ctx.props.render(h, params)
  }
}
複製代碼

利用 render函數定製表格內的內容api

使用

import { Component } from 'vue-property-decorator'
import { CreateElement } from 'vue/types/umd'
import ComList from '@/components/ComList/index.vue'
import Page from '@/mixins/pageMixins'

@Component({
  components: {
    ComList
  }
})
export default class Work extends Page {
  
  fetchList = this.$api.WorkOrder.getList

  columns: Array<object> = [
    {
      label: '工單編號',
      prop: 'id'
    },
    {
      label: '問題類型',
      prop: 'type',
      formatter: this.formatterType
    },
    {
      label: '問題標題',
      prop: 'title'
    },
    {
      label: '狀態',
      prop: 'status',
      render: (h: CreateElement, { row }: any) => {
        return h('el-tag', {
          props: {
            type: row.status === 1 ? 'success' : 'danger'
          }
        }, row.status === 1 ? '啓用' : '停用')
      }
    },
    {
      label: '問題詳情',
      prop: 'content'
    },
    {
      label: '提交時間',
      prop: 'create_time'
    },
    {
      slot: 'operation'
    }
  ]

  typeOption: Array<object> = []

  formatterType (row: any) {
    let str = ''
    this.typeOption.forEach((el: any) => {
      if (el.id === row.type) str = el.group_name 
    })
    return str
  }
}
複製代碼

不知爲什麼這個語法只能渲染 element-ui裏的組件,若是div等則沒法放入內容。app

相關文章
相關標籤/搜索