推薦 vue2、vue3 中功能最強大的表格元件,效能最強大的表格元件推薦、可編輯表格推薦

可不简单發表於2024-11-21

vxe-table 是一個vue的表格元件,支援可編輯和虛擬滾動高效能表格,公司使用了幾年的表格,grid 渲染器擴充套件功能非常強大。

npm install vxe-pc-ui@4.3.2 vxe-table@4.9.3
// ...
import VxeUI from 'vxe-pc-ui'
import 'vxe-pc-ui/lib/style.css'
import VxeUITable from 'vxe-table'
import 'vxe-table/lib/style.css'
// ...

createApp(App).use(VxeUI).use(VxeUITable).mount('#app')
// ...

基礎使用

<template>
  <div>
    <vxe-table
      :data="tableData">
      <vxe-column type="seq" width="70"></vxe-column>
      <vxe-column field="name" title="Name"></vxe-column>
      <vxe-column field="sex" title="Sex"></vxe-column>
      <vxe-column field="age" title="Age"></vxe-column>
    </vxe-table>
  </div>
</template>

<script>
export default {
  data () {
    const tableData = [
      { id: 10001, name: 'Test1', role: 'Develop', sex: 'Man', age: 28, address: 'test abc' },
      { id: 10002, name: 'Test2', role: 'Test', sex: 'Women', age: 22, address: 'Guangzhou' },
      { id: 10003, name: 'Test3', role: 'PM', sex: 'Man', age: 32, address: 'Shanghai' },
      { id: 10004, name: 'Test4', role: 'Designer', sex: 'Women', age: 24, address: 'Shanghai' }
    ]
    return {
      tableData
    }
  }
}
</script>

多選

單選

單元格合併

標題字首提示

凍結列

樹表格

<template>
  <div>
    <vxe-grid v-bind="gridOptions"></vxe-grid>
  </div>
</template>

<script>
export default {
  data () {
    const gridOptions = {
      border: true,
      treeConfig: {
        rowField: 'id',
        childrenField: 'children'
      },
      columns: [
        { type: 'seq', width: 70 },
        { field: 'name', title: 'Name', minWidth: 300, treeNode: true },
        { field: 'size', title: 'Size' },
        { field: 'type', title: 'Type' },
        { field: 'date', title: 'Date' }
      ],
      data: [
        { id: 10000, name: 'Test1', type: 'mp3', size: 1024, date: '2020-08-01' },
        {
          id: 10050,
          name: 'Test2',
          type: 'mp4',
          size: 0,
          date: '2021-04-01',
          children: [
            {
              id: 24300,
              name: 'Test3',
              type: 'avi',
              size: 1024,
              date: '2020-03-01',
              children: [
                { id: 20045, name: 'Test4', type: 'html', size: 600, date: '2021-04-01' },
                {
                  id: 10053,
                  name: 'Test5',
                  type: 'avi',
                  size: 0,
                  date: '2021-04-01',
                  children: [
                    { id: 24330, name: 'Test6', type: 'txt', size: 25, date: '2021-10-01' },
                    { id: 21011, name: 'Test7', type: 'pdf', size: 512, date: '2020-01-01' },
                    { id: 22200, name: 'Test8', type: 'js', size: 1024, date: '2021-06-01' }
                  ]
                }
              ]
            }
          ]
        },
        {
          id: 23666,
          name: 'Test9',
          type: 'xlsx',
          size: 2048,
          date: '2020-11-01',
          children: [
            {
              id: 23677,
              name: 'Test10',
              type: 'js',
              size: 1024,
              date: '2021-06-01',
              children: [
                { id: 23671, name: 'Test11', type: 'js', size: 1024, date: '2021-06-01' },
                { id: 23672, name: 'Test12', type: 'js', size: 1024, date: '2021-06-01' }
              ]
            },
            {
              id: 23688,
              name: 'Test13',
              type: 'js',
              size: 1024,
              date: '2021-06-01',
              children: [
                { id: 23681, name: 'Test14', type: 'js', size: 1024, date: '2021-06-01' },
                { id: 23682, name: 'Test15', type: 'js', size: 1024, date: '2021-06-01' }
              ]
            }
          ]
        },
        {
          id: 24555,
          name: 'Test16',
          type: 'avi',
          size: 224,
          date: '2020-10-01',
          children: [
            { id: 24566, name: 'Test17', type: 'js', size: 1024, date: '2021-06-01' },
            { id: 24577, name: 'Test18', type: 'js', size: 1024, date: '2021-06-01' }
          ]
        }
      ]
    }
    return {
      gridOptions
    }
  }
}
</script>

行與列拖拽調整順序

<template>
  <div>
    <vxe-button status="success" @click="resultEvent">獲取資料</vxe-button>
    <vxe-grid ref="gridRef" v-bind="gridOptions"></vxe-grid>
  </div>
</template>

<script>
export default {
  data () {
    const gridOptions = {
      border: true,
      columnConfig: {
        useKey: true,
        drag: true
      },
      rowConfig: {
        useKey: true,
        drag: true
      },
      columns: [
        { field: 'name', title: 'Name' },
        { field: 'role', title: 'Role', dragSort: true },
        { field: 'sex', title: 'Sex' },
        { field: 'age', title: 'Age' },
        { field: 'address', title: 'Address' }
      ],
      data: [
        { id: 10001, name: 'Test1', role: 'Develop', sex: 'Man', age: 28, address: 'test abc' },
        { id: 10002, name: 'Test2', role: 'Test', sex: 'Women', age: 22, address: 'Guangzhou' },
        { id: 10003, name: 'Test3', role: 'PM', sex: 'Man', age: 32, address: 'Shanghai' },
        { id: 10004, name: 'Test4', role: 'Designer', sex: 'Women', age: 24, address: 'Shanghai' }
      ]
    }
    return {
      gridOptions
    }
  },
  methods: {
    resultEvent () {
      const $grid = this.$refs.gridRef
      if ($grid) {
        const { visibleColumn } = $grid.getTableColumn()
        console.log(visibleColumn)
      }
    }
  }
}
</script>

可編輯表格

<template>
  <div>
    <vxe-grid v-bind="gridOptions"></vxe-grid>
  </div>
</template>

<script>
export default {
  data () {
    const gridOptions = {
      border: true,
      showOverflow: true,
      editConfig: {
        trigger: 'click',
        mode: 'cell'
      },
      columns: [
        { type: 'seq', width: 70 },
        { field: 'name', title: 'Name', editRender: { name: 'input' } },
        { field: 'sex', title: 'Sex', editRender: { name: 'input' } },
        { field: 'age', title: 'Age', editRender: { name: 'input' } }
      ],
      data: [
        { id: 10001, name: 'Test1', role: 'Develop', sex: 'Man', age: 28, address: 'test abc' },
        { id: 10002, name: 'Test2', role: 'Test', sex: 'Women', age: 22, address: 'Guangzhou' },
        { id: 10003, name: 'Test3', role: 'PM', sex: 'Man', age: 32, address: 'Shanghai' },
        { id: 10004, name: 'Test4', role: 'Designer', sex: 'Women', age: 24, address: 'Shanghai' }
      ]
    }
    return {
      gridOptions
    }
  }
}
</script>

資料校驗

<template>
  <div>
    <div>
      <vxe-button @click="validEvent">校驗變動資料</vxe-button>
      <vxe-button @click="fullValidEvent">校驗全量資料</vxe-button>
    </div>
    <vxe-grid ref="gridRef" v-bind="gridOptions"></vxe-grid>
  </div>
</template>

<script>
import { VxeUI } from 'vxe-table'
export default {
  data () {
    const gridOptions = {
      border: true,
      showOverflow: true,
      keepSource: true,
      height: 300,
      editConfig: {
        trigger: 'click',
        mode: 'row',
        showStatus: true
      },
      editRules: {
        role: [
          { required: true, message: '必須填寫' }
        ]
      },
      columns: [
        { type: 'checkbox', width: 60 },
        { type: 'seq', width: 70 },
        { field: 'name', title: 'Name', editRender: { name: 'VxeInput' } },
        { field: 'role', title: 'Role', editRender: { name: 'VxeInput' } },
        { field: 'sex', title: 'Sex', editRender: { name: 'VxeInput' } },
        { field: 'age', title: 'Age', editRender: { name: 'VxeInput' } },
        { field: 'date', title: 'Date', editRender: { name: 'VxeInput' } }
      ],
      data: [
        { id: 10001, name: 'Test1', role: 'Develop', sex: '0', age: 28, address: 'test abc' },
        { id: 10002, name: '', role: 'Test', sex: '1', age: 22, address: 'Guangzhou' },
        { id: 10003, name: 'Test3', role: 'PM', sex: '', age: 32, address: 'Shanghai' },
        { id: 10004, name: 'Test4', role: 'Designer', sex: '', age: 23, address: 'test abc' },
        { id: 10005, name: '', role: '', sex: '1', age: 30, address: 'Shanghai' },
        { id: 10006, name: 'Test6', role: 'Designer', sex: '1', age: 21, address: 'test abc' }
      ]
    }
    return {
      gridOptions
    }
  },
  methods: {
    async validEvent () {
      const $grid = this.$refs.gridRef
      if ($grid) {
        const errMap = await $grid.validate()
        if (errMap) {
          VxeUI.modal.message({ status: 'error', content: '校驗不透過!' })
        } else {
          VxeUI.modal.message({ status: 'success', content: '校驗成功!' })
        }
      }
    },
    async fullValidEvent () {
      const $grid = this.$refs.gridRef
      if ($grid) {
        const errMap = await $grid.validate(true)
        if (errMap) {
          VxeUI.modal.message({ status: 'error', content: '校驗不透過!' })
        } else {
          VxeUI.modal.message({ status: 'success', content: '校驗成功!' })
        }
      }
    }
  }
}
</script>

表格搜尋

<template>
  <div>
    <p>
      <vxe-input v-model="filterName" type="search" placeholder="試試全表搜尋" @keyup="searchEvent"></vxe-input>
    </p>

    <vxe-grid v-bind="gridOptions" class="mylist-grid"></vxe-grid>
  </div>
</template>

<script>
import XEUtils from 'xe-utils'
export default {
  data () {
    const tableAllData = [
      { id: 10001, name: 'Test1', role: 'Develop', sex: '0', age: 28, amount: 888, address: 'test abc' },
      { id: 10002, name: 'Test2', role: 'Test', sex: '1', age: 22, amount: 666, address: 'Guangzhou' },
      { id: 10003, name: 'Test3', role: 'PM', sex: '1', age: 32, amount: 89, address: 'Shanghai' },
      { id: 10004, name: 'Test4', role: 'Designer', sex: '0', age: 23, amount: 1000, address: 'test abc' },
      { id: 10005, name: 'Test5', role: 'Develop', sex: '0', age: 30, amount: 999, address: 'Shanghai' },
      { id: 10006, name: 'Test6', role: 'Designer', sex: '0', age: 21, amount: 998, address: 'test abc' },
      { id: 10007, name: 'Test7', role: 'Test', sex: '1', age: 29, amount: 2000, address: 'test abc' },
      { id: 10008, name: 'Test8', role: 'Develop', sex: '1', age: 35, amount: 999, address: 'test abc' },
      { id: 10009, name: 'Test9', role: 'Test', sex: '1', age: 26, amount: 2000, address: 'test abc' },
      { id: 100010, name: 'Test10', role: 'Develop', sex: '1', age: 21, amount: 666, address: 'test abc' }
    ]
    const gridOptions = {
      border: true,
      height: 400,
      columnConfig: {
        useKey: true
      },
      rowConfig: {
        useKey: true
      },
      columns: [
        { type: 'seq', width: 70 },
        { field: 'name', title: 'Name', type: 'html' },
        { field: 'sex', title: 'Sex', type: 'html' },
        { field: 'age', title: 'Age', type: 'html' },
        { field: 'address', title: 'Address', type: 'html' }
      ],
      data: []
    }
    return {
      gridOptions,
      filterName: '',
      tableAllData
    }
  },
  methods: {
    handleSearch () {
      const filterVal = String(this.filterName).trim().toLowerCase()
      if (filterVal) {
        const filterRE = new RegExp(filterVal, 'gi')
        const searchProps = ['name', 'role', 'age', 'address']
        const rest = this.tableAllData.filter(item => searchProps.some(key => String(item[key]).toLowerCase().indexOf(filterVal) > -1))
        this.gridOptions.data = rest.map(row => {
          // 搜尋為克隆資料,不會汙染源資料
          const item = XEUtils.clone(row)
          searchProps.forEach(key => {
            item[key] = String(item[key]).replace(filterRE, match => `<span class="keyword-highlight">${match}</span>`)
          })
          return item
        })
      } else {
        this.gridOptions.data = this.tableAllData
      }
    },
    // 節流函式,間隔500毫秒觸發搜尋
    searchEvent: XEUtils.throttle(function () {
      this.handleSearch()
    }, 500, { trailing: true, leading: true })
  },
  created () {
    this.handleSearch()
  }
}
</script>

<style lang="scss" scoped>
.mylist-grid {
  ::v-deep(.keyword-highlight)  {
    background-color: #FFFF00;
  }
}
</style>

相關文章