Vue的高级表格组件库【vxe-table】

简介: Vue的高级表格组件库【vxe-table】

前言

hello world欢迎来到前端的新世界


😜当前文章系列专栏:前端系列文章

🐱‍👓博主在前端领域还有很多知识和技术需要掌握,正在不断努力填补技术短板。(如果出现错误,感谢大家指出)🌹

💖感谢大家支持!您的观看就是作者创作的动力

vxe-table

一款专门用来对Vue3表格进行复杂操作的ui组件库,虚拟滚动,普通表格的行拖拽,表格的全屏展示,表格的全键盘操作,禁用编辑等。

官网

官网地址

下载

npm install xe-utils vxe-table

配置在main.js或者main.ts里面

import { App, createApp } from 'vue'
import VXETable from 'vxe-table'
import 'vxe-table/lib/style.css'
function useTable (app: App) {
  app.use(VXETable)
}
createApp(App).use(useTable).mount('#app')

实现表头拖拽

直接复制

<template>
  <div>
    <vxe-grid v-bind="gridOptions">
      <template #toolbar_buttons>
        <vxe-button @click="gridOptions.align = 'left'">居左</vxe-button>
        <vxe-button @click="gridOptions.align = 'center'">居中</vxe-button>
        <vxe-button @click="gridOptions.align = 'right'">居右</vxe-button>
      </template>
    </vxe-grid>
  </div>
</template>
<script lang="ts" setup>
import { reactive } from 'vue'
import { VxeGridProps } from 'vxe-table'
interface RowVO {
  id: number
  name: string
  nickname: string
  role: string
  sex: string
  age: number
  address: string
}
const gridOptions = reactive<VxeGridProps<RowVO>>({
  border: true,
  height: 300,
  align: null,
  columnConfig: {
    resizable: true
  },
  columns: [
    { type: 'seq', width: 50 },
    { field: 'name', title: 'name' },
    { field: 'sex', title: 'sex' },
    { field: 'address', title: 'Address' }
  ],
  toolbarConfig: {
    slots: {
      buttons: 'toolbar_buttons'
    }
  },
  data: [
    { id: 10001, name: 'Test1', nickname: 'T1', role: 'Develop', sex: 'Man', age: 28, address: 'Shenzhen' },
    { id: 10002, name: 'Test2', nickname: 'T2', role: 'Test', sex: 'Women', age: 22, address: 'Guangzhou' },
    { id: 10003, name: 'Test3', nickname: 'T3', role: 'PM', sex: 'Man', age: 32, address: 'Shanghai' },
    { id: 10004, name: 'Test4', nickname: 'T4', role: 'Designer', sex: 'Women', age: 23, address: 'Shenzhen' },
    { id: 10005, name: 'Test5', nickname: 'T5', role: 'Develop', sex: 'Women', age: 30, address: 'Shanghai' },
    { id: 10006, name: 'Test6', nickname: 'T6', role: 'Designer', sex: 'Women', age: 21, address: 'Shenzhen' },
    { id: 10007, name: 'Test7', nickname: 'T7', role: 'Test', sex: 'Man', age: 29, address: 'Shenzhen' },
    { id: 10008, name: 'Test8', nickname: 'T8', role: 'Develop', sex: 'Man', age: 35, address: 'Shenzhen' }
  ]
})
</script>

树形表格

<template>
  <div>
    <vxe-toolbar>
      <template #buttons>
        <vxe-button @click="expandAllEvent">展开所有</vxe-button>
        <vxe-button @click="claseExpandEvent">收起所有</vxe-button>
      </template>
    </vxe-toolbar>
    <vxe-table
      show-overflow
      height="400"
      ref="tableRef"
      :loading="loading"
      :tree-config="{transform: true}"
      :scroll-y="{enabled: true, gt: 20}"
      :data="tableData">
      <vxe-column type="seq" width="200" tree-node></vxe-column>
      <vxe-column field="id" title="Id"></vxe-column>
      <vxe-column field="name" title="Name"></vxe-column>
    </vxe-table>
  </div>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { VxeTableInstance } from 'vxe-table'
interface RowVO {
  id: number
  parentId: number | null
  name: string
}
const tableRef = ref<VxeTableInstance<RowVO>>()
const loading = ref(false)
const tableData = ref<RowVO[]>([])
const loadList = () => {
  loading.value = true
  fetch('/resource/json/provinces_list.json').then(res => res.json()).then((data: RowVO[]) => {
    tableData.value = data
    loading.value = false
  })
}
const expandAllEvent = () => {
  const $table = tableRef.value
  if ($table) {
    $table.setAllTreeExpand(true)
  }
}
const claseExpandEvent = () => {
  const $table = tableRef.value
  if ($table) {
    $table.clearTreeExpand()
  }
}
loadList()
</script>

全键盘操作

template

<vxe-toolbar :refresh="{query: findList}">
          <template #buttons>
            <vxe-button>
              <template #default>新增操作</template>
              <template #dropdowns>
                <vxe-button type="text" @click="insertEvent(null)">从第一行插入</vxe-button>
                <vxe-button type="text" @click="insertEvent(-1)">从最后插入</vxe-button>
                <vxe-button type="text" @click="insertEvent($refs.xTable.getData(100))">插入到 100 行</vxe-button>
                <vxe-button type="text" @click="insertEvent($refs.xTable.getData(400))">插入到 400 行</vxe-button>
              </template>
            </vxe-button>
            <vxe-button>
              <template #default>删除操作</template>
              <template #dropdowns>
                <vxe-button type="text" @click="$refs.xTable.removeCheckboxRow()">删除选中</vxe-button>
                <vxe-button type="text" @click="$refs.xTable.remove($refs.xTable.getData(0))">删除第一行</vxe-button>
                <vxe-button type="text" @click="$refs.xTable.remove($refs.xTable.getData($refs.xTable.getData().length - 1))">删除最后一行</vxe-button>
                <vxe-button type="text" @click="$refs.xTable.remove($refs.xTable.getData(100))">删除第 100 行</vxe-button>
              </template>
            </vxe-button>
            <vxe-button>
              <template #default>校验操作</template>
              <template #dropdowns>
                <vxe-button type="text" @click="validEvent">快速校验</vxe-button>
                <vxe-button type="text" @click="fullValidEvent">完整快速校验</vxe-button>
                <vxe-button type="text" @click="selectValidEvent">选中行校验</vxe-button>
              </template>
            </vxe-button>
            <vxe-button @click="getInsertEvent">获取新增</vxe-button>
            <vxe-button @click="getRemoveEvent">获取删除</vxe-button>
            <vxe-button @click="getUpdateEvent">获取修改</vxe-button>
            <vxe-button>
              <template #default>滚动操作</template>
              <template #dropdowns>
                <vxe-button type="text" @click="$refs.xTable.scrollToRow($refs.xTable.getData(10))">滚动到第 10 行</vxe-button>
                <vxe-button type="text" @click="$refs.xTable.scrollToRow($refs.xTable.getData(400))">滚动第 400 行</vxe-button>
                <vxe-button type="text" @click="$refs.xTable.scrollToColumn($refs.xTable.getColumns(1))">滚动第 1 列</vxe-button>
                <vxe-button type="text" @click="$refs.xTable.scrollToColumn($refs.xTable.getColumns(10))">滚动第 10 列</vxe-button>
              </template>
            </vxe-button>
          </template>
        </vxe-toolbar>
        <vxe-table
          border
          show-overflow
          keep-source
          ref="xTable"
          height="300"
          :column-config="{resizable: true}"
          :loading="demo1.loading"
          :edit-rules="demo1.validRules"
          :mouse-config="{selected: true}"
          :edit-config="{trigger: 'dblclick', mode: 'cell', showStatus: true}"
          :keyboard-config="{isArrow: true, isDel: true, isEnter: true, isTab: true, isEdit: true}">
          <vxe-column type="checkbox" width="60"></vxe-column>
          <vxe-column type="seq" width="100"></vxe-column>
          <vxe-column field="name" title="Name" sortable width="200" :edit-render="{autofocus: '.vxe-input--inner'}">
            <template #edit="scope">
              <vxe-input v-model="scope.row.name" type="text" @change="$refs.xTable.updateStatus(scope)"></vxe-input>
            </template>
          </vxe-column>
          <vxe-column field="age" title="Age" width="200" :edit-render="{autofocus: '.vxe-input--inner'}">
            <template #edit="scope">
              <vxe-input v-model="scope.row.age" type="text" @change="$refs.xTable.updateStatus(scope)"></vxe-input>
            </template>
          </vxe-column>
          <vxe-column field="sex" title="Sex" width="200" :edit-render="{autofocus: '.vxe-input--inner'}">
            <template #edit="scope">
              <vxe-input v-model="scope.row.sex" type="text" @change="$refs.xTable.updateStatus(scope)"></vxe-input>
            </template>
          </vxe-column>
          <vxe-column field="rate" title="Rate" width="200"></vxe-column>
          <vxe-column field="region" title="Region" width="200"></vxe-column>
          <vxe-column field="time" title="Time" width="200"></vxe-column>
          <vxe-column field="address" title="Address" width="300" show-overflow></vxe-column>
          <vxe-column field="updateTime" title="UpdateTime" width="200"></vxe-column>
          <vxe-column field="createTime" title="CreateTime" width="200"></vxe-column>
        </vxe-table>

script

import { defineComponent, reactive, ref } from 'vue'
        import { VXETable, VxeTableInstance, VxeTablePropTypes } from 'vxe-table'
        export default defineComponent({
          setup () {
            const xTable = ref<VxeTableInstance>()
            const demo1 = reactive({
              loading: false,
              validRules: {
                name: [
                  { required: true, message: 'app.body.valid.rName' },
                  { min: 3, max: 50, message: '名称长度在 3 到 50 个字符' }
                ],
                sex: [
                  { required: true, message: '性别必须填写' }
                ]
              } as VxeTablePropTypes.ValidConfig
            })
            const mockList = (size: number) => {
              const list: any[] = []
              for (let index = 0; index < size; index++) {
                list.push({
                  checked: false,
                  name: `名称${index}`,
                  sex: '0',
                  num: 123,
                  age: 18,
                  num2: 234,
                  rate: 3,
                  address: 'shenzhen'
                })
              }
              return list
            }
            const findList = () => {
              demo1.loading = true
              return new Promise(resolve => {
                setTimeout(() => {
                  const tableData = mockList(600)
                  // 阻断 vue 对大数组的监听,避免 vue 绑定大数据造成短暂的卡顿
                  const $table = xTable.value
                  if ($table) {
                    $table.loadData(tableData)
                  }
                  resolve(null)
                  demo1.loading = false
                }, 300)
              })
            }
            const validEvent = async () => {
              const $table = xTable.value
              const errMap = await $table.validate()
              if (errMap) {
                VXETable.modal.message({ status: 'error', content: '校验不通过!' })
              } else {
                VXETable.modal.message({ status: 'success', content: '校验成功!' })
              }
            }
            const fullValidEvent = async () => {
              const $table = xTable.value
              const errMap = await $table.fullValidate()
              if (errMap) {
                const msgList: string[] = []
                Object.values(errMap).forEach((errList) => {
                  errList.forEach(params => {
                    const { rowIndex, column, rules } = params
                    rules.forEach(rule => {
                      msgList.push(`第 ${rowIndex + 1} 行 ${column.title} 校验错误:${rule.message}`)
                    })
                  })
                })
                VXETable.modal.message({
                  status: 'error',
                  slots: {
                    default () {
                      return [
                        <div class="red" style="max-height: 400px;overflow: auto;">
                          {
                            msgList.map(msg => {
                              return <div>{ msg }</div>
                            })
                          }
                        </div>
                      ]
                    }
                  }
                })
              } else {
                VXETable.modal.message({ status: 'success', content: '校验成功!' })
              }
            }
            const selectValidEvent = async () => {
              const $table = xTable.value
              const selectRecords = $table.getCheckboxRecords()
              if (selectRecords.length > 0) {
                const errMap = await $table.validate(selectRecords).catch(errMap => errMap)
                if (errMap) {
                  VXETable.modal.message({ status: 'error', content: '校验不通过!' })
                } else {
                  VXETable.modal.message({ status: 'success', content: '校验成功!' })
                }
              } else {
                VXETable.modal.message({ status: 'warning', content: '未选中数据!' })
              }
            }
            const insertEvent = (row: any) => {
              const $table = xTable.value
              const record = {
                checked: false
              }
              $table.insertAt(record, row).then(({ row }) => {
                $table.setEditRow(row)
              })
            }
            const getInsertEvent = () => {
              const $table = xTable.value
              const insertRecords = $table.getInsertRecords()
              VXETable.modal.alert(insertRecords.length)
            }
            const getRemoveEvent = () => {
              const $table = xTable.value
              const removeRecords = $table.getRemoveRecords()
              VXETable.modal.alert(removeRecords.length)
            }
            const getUpdateEvent = () => {
              const $table = xTable.value
              const updateRecords = $table.getUpdateRecords()
              VXETable.modal.alert(updateRecords.length)
            }
            findList()
            return {
              xTable,
              demo1,
              findList,
              validEvent,
              fullValidEvent,
              selectValidEvent,
              insertEvent,
              getInsertEvent,
              getRemoveEvent,
              getUpdateEvent
            }
          }
        })

后言

创作不易,要是本文章对广大读者有那么一点点帮助 不妨三连支持一下,您的鼓励就是博主创作的动力


目录
相关文章
|
11天前
|
缓存 JavaScript 前端开发
vue学习第四章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中计算属性的基本与复杂使用、setter/getter、与methods的对比及与侦听器的总结。如果你觉得有用,请关注我,将持续更新更多优质内容!🎉🎉🎉
27 1
vue学习第四章
|
11天前
|
JavaScript 前端开发
vue学习第九章(v-model)
欢迎来到我的博客,我是瑞雨溪,一名热爱JavaScript与Vue的大一学生,自学前端2年半,正向全栈进发。此篇介绍v-model在不同表单元素中的应用及修饰符的使用,希望能对你有所帮助。关注我,持续更新中!🎉🎉🎉
23 1
vue学习第九章(v-model)
|
11天前
|
JavaScript 前端开发 开发者
vue学习第十章(组件开发)
欢迎来到瑞雨溪的博客,一名热爱JavaScript与Vue的大一学生。本文深入讲解Vue组件的基本使用、全局与局部组件、父子组件通信及数据传递等内容,适合前端开发者学习参考。持续更新中,期待您的关注!🎉🎉🎉
24 1
vue学习第十章(组件开发)
|
5天前
|
前端开发 JavaScript 测试技术
Vue3中v-model在处理自定义组件双向数据绑定时,如何避免循环引用?
Web 组件化是一种有效的开发方法,可以提高项目的质量、效率和可维护性。在实际项目中,要结合项目的具体情况,合理应用 Web 组件化的理念和技术,实现项目的成功实施和交付。通过不断地探索和实践,将 Web 组件化的优势充分发挥出来,为前端开发领域的发展做出贡献。
19 8
|
5天前
|
JavaScript
在 Vue 3 中,如何使用 v-model 来处理自定义组件的双向数据绑定?
需要注意的是,在实际开发中,根据具体的业务需求和组件设计,可能需要对上述步骤进行适当的调整和优化,以确保双向数据绑定的正确性和稳定性。同时,深入理解 Vue 3 的响应式机制和组件通信原理,将有助于更好地运用 `v-model` 实现自定义组件的双向数据绑定。
|
16天前
|
JavaScript 前端开发 UED
vue学习第二章
欢迎来到我的博客!我是一名自学了2年半前端的大一学生,熟悉JavaScript与Vue,目前正在向全栈方向发展。如果你从我的博客中有所收获,欢迎关注我,我将持续更新更多优质文章。你的支持是我最大的动力!🎉🎉🎉
26 3
|
16天前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript和Vue的大一学生。自学前端2年半,熟悉JavaScript与Vue,正向全栈方向发展。博客内容涵盖Vue基础、列表展示及计数器案例等,希望能对你有所帮助。关注我,持续更新中!🎉🎉🎉
36 2
|
JavaScript 前端开发 测试技术
基于 vue3.0 从 0-1 搭建组件库(一)
基于 vue3 效仿 element-plus 从零实现组件库
934 0
基于 vue3.0 从 0-1 搭建组件库(一)
|
17天前
|
JavaScript 前端开发
如何在 Vue 项目中配置 Tree Shaking?
通过以上针对 Webpack 或 Rollup 的配置方法,就可以在 Vue 项目中有效地启用 Tree Shaking,从而优化项目的打包体积,提高项目的性能和加载速度。在实际配置过程中,需要根据项目的具体情况和需求,对配置进行适当的调整和优化。
|
17天前
|
存储 缓存 JavaScript
在 Vue 中使用 computed 和 watch 时,性能问题探讨
本文探讨了在 Vue.js 中使用 computed 计算属性和 watch 监听器时可能遇到的性能问题,并提供了优化建议,帮助开发者提高应用性能。