赞
踩
elemetui自定义表格实现可拖拽列、显示隐藏列、数据汇总、自适应宽度
使用前需要先安装一个包
npm i -S vuedraggable
使用的时候需要注意几个地方:
第一个是必须设置row-key,你的值必须是唯一值,不一定是id也可以是其他的
第二个是你需要设置两个对象:Col和dropCol,这两个对象是保存每一列的label和prop的,虽然这两个是一样的,但是必须要设置两个,否则就会导致你拖拽替换只会替换每一列对应的值不会替换label。对象形式如下:
- const Col = ref([
- {
- label: '零件名称',
- prop: 'partName',
- status:true
- },
- {
- label: '批次号',
- prop: 'batchNo',
- status:true
- },
- {
- label: '发票号',
- prop: 'invoiceNo',
- status:true
- },
- {
- label: '订单号',
- prop: 'orderNo',
- status:true
- },
- {
- label: '箱号',
- prop: 'boxNo',
- status:true
- },
- {
- label: '小箱号',
- prop: 'caseNo',
- status:true
- }
- ])
- <el-table :data="roleList" show-summary row-key="id"
- :summary-method="getSummaries">
- <template v-for="(col,index) in Col" :key="index" >
- <el-table-column :width="index==0? flexColumnWidth(col.prop, roleList):'300'"
- :label="col.label" :prop="col.prop" align="center" />
- </template>
-
- </el-table>
然后下面是列拖拽的方法
- //列拖拽
- function columnDrop() {
- const wrapperTr = document.querySelector('.el-table__header-wrapper tr')
- Sortable.create(wrapperTr, {
- animation: 180,
- delay: 0,
- onEnd: evt => {
- // 过滤掉dropCol为false的项
- const oldItem = Col.value[evt.oldIndex];
- Col.value.splice(evt.oldIndex, 1);
- Col.value.splice(evt.newIndex, 0, oldItem);
- console.log(evt.oldIndex,evt.newIndex);
-
- }
- })
- }
-
- //需要在onMouted函数中调用一次
- onMounted(() => {
-
- columnDrop()
- })
给每一列添加这个代码
:width="flexColumnWidth(dropCol[1].prop, tableData)"
如果只是想在某一列添加可以这样,宽度自定义
:width="index==0? flexColumnWidth(col.prop, roleList):'300'"
方法如下:
注意如果那一列的数据存在某一个是空值那么那一项就会不进入自适应宽度,把下面的注释掉就可以了;
- // 自适应表格列宽
- const flexColumnWidth = (str, tableData, flag = 'max') => {
- // str为该列的字段名(传字符串);tableData为该表格的数据源(传变量);
- // flag为可选值,可不传该参数,传参时可选'max'或'equal',默认为'max'
- // flag为'max'则设置列宽适配该列中最长的内容,flag为'equal'则设置列宽适配该列中第一行内容的长度。
-
- str = str + ''
- let columnContent = ''
- if (!tableData || !tableData.length || tableData.length === 0 || tableData === undefined) {
- return
- }
- if (!str || !str.length || str.length === 0 || str === undefined) {
- return
- }
-
- if (flag === 'equal') {
- // 获取该列中第一个不为空的数据(内容)
- for (let i = 0; i < tableData.length; i++) {
- if (tableData[i][str].length > 0) {
- // console.log('该列数据[0]:', tableData[0][str])
- columnContent = tableData[i][str]
- break
- }
- }
- } else {
- // 获取该列中最长的数据(内容)
- let index = 0
- for (let i = 0; i < tableData.length; i++) {
- // 数据为空跳出循环
- // if (tableData[i][str] === null) {
- // return
- // }
- const now_temp = tableData[i][str] + ''
- const max_temp = tableData[index][str] + ''
- if (now_temp.length > max_temp.length) {
- index = i
- }
- }
- columnContent = tableData[index][str]
- }
- // console.log('该列数据[i]:', columnContent)
- // 以下分配的单位长度可根据实际需求进行调整
- let flexWidth = 0
- columnContent = columnContent + ''
- for (const char of columnContent) {
- if ((char >= 'A' && char <= 'Z') || (char >= 'a' && char <= 'z')) {
- // 如果是英文字符,为字符分配8个单位宽度
- flexWidth += 12
- } else if (char >= '\u4e00' && char <= '\u9fa5') {
- // 如果是中文字符,为字符分配15个单位宽度
- flexWidth += 15
- } else {
- // 其他种类字符,为字符分配15个单位宽度
- flexWidth += 12
- }
- }
- if (flexWidth < 80) {
- // 设置最小宽度
- flexWidth = 80
- }
- // if (flexWidth > 250) {
- // // 设置最大宽度
- // flexWidth = 250
- // }
- return flexWidth + 'px'
- }
通过v-if命令动态修改你每一列是否显示
设置一个对象,包含你每一列的项
- const dropCol = ref([
- {
- label: '零件名称',
- prop: 'partName',
- status:true
- },
- {
- label: '批次号',
- prop: 'batchNo',
- status:true
- },
- {
- label: '发票号',
- prop: 'invoiceNo',
- status:true
- },
- {
- label: '订单号',
- prop: 'orderNo',
- status:true
- },
- {
- label: '箱号',
- prop: 'boxNo',
- status:true
- },
- {
- label: '小箱号',
- prop: 'caseNo',
- status:true
- }
- ])
控制列的面板:el-popover是一个弹框,然后里面自定义多选框内容
- <el-popover placement="bottom-start" :width="600" trigger="hover">
- <transition name="fade">
- <div>
- <div>选择需要显示的列</div>
- <div>
- <el-checkbox v-model="checkAll" @change="handleCheckAllChange">全选</el-checkbox>
- <el-checkbox v-for="(item, index) in dropCol" :key="index" @change="handleCheckedBoxChange" v-model="item.status">{{item.label}}</el-checkbox>
- </div>
- </div>
- </transition>
- <template #reference>
- <el-button icon="Setting">显示列</el-button>
- </template>
- </el-popover>
- function handleCheckAllChange() {
- dropCol.value.forEach(item => {
- item.status = checkAll.value;
- });
- }
- function handleCheckedBoxChange() {
- const allTrue = dropCol.value.every(item => item.status === true);
- Col.value=dropCol.value.filter(item=>item.status==true)
- if (allTrue) {
- checkAll.value = true
- } else {
- checkAll.value = false
- }
-
- }
表格需要添加show-summary :summary-method="getSummaries"
<el-table :data="roleList" show-summary :summary-method="getSummaries">
方法如下:
- // 自定义汇总方法
- const getSummaries = (param) => {
- const { columns, data } = param
- const sums = []
- columns.forEach((column, index) => {
- if (index === 0) {
- sums[index] = '总数'
- return
- }
- console.log(column.property);
- // 将所有元素的值转换成数字类型
- const values = data.map((item) => Number(item[column.property]))
- console.log(values.some((val) => Number.isNaN(val)));
- // every 只要有一个是数字,就会返回true
- // 判断数组中的数据是否是数字类型 some 只要存在一个是NaN那么就返回false
- if (!values.some((value) => Number.isNaN(value))) {
- sums[index] = ` ${values.reduce((prev, curr) => {
- const value = Number(curr)
- if (!Number.isNaN(value)) {
- return prev + curr
- } else {
- return prev
-
- }
- }, 0)}`
- } else {
- sums[index] = '/'
- }
- })
-
- return sums
- }
- /* order默认值为0,只需将表体order置为1即可移到最后,这样合计行就上移到表体上方 */
- ::v-deep .el-table__body-wrapper {
- order: 1;
- }
- ::v-deep .el-table__fixed-body-wrapper {
- top: 96px !important;
- }
- ::v-deep .el-table__fixed-footer-wrapper {
- z-index: 0;
- }
template部分
- <template>
- <div>
- <el-popover placement="bottom-start" :width="600" trigger="hover">
- <transition name="fade">
- <div>
- <div>选择需要显示的列</div>
- <div>
- <el-checkbox v-model="checkAll" @change="handleCheckAllChange">全选</el-checkbox>
- <el-checkbox v-for="(item, index) in dropCol" :key="index" @change="handleCheckedBoxChange" v-model="item.status">{{item.label}}</el-checkbox>
- </div>
- </div>
- </transition>
- <template #reference>
- <el-button icon="Setting">显示列</el-button>
- </template>
- </el-popover>
-
- <el-table :data="roleList" show-summary row-key="id"
- :summary-method="getSummaries">
- <template v-for="(col,index) in Col" :key="index" >
- <el-table-column :width="index==0? flexColumnWidth(col.prop, roleList):'300'"
- :label="col.label" :prop="col.prop" align="center" />
- </template>
-
- </el-table>
- </div>
- </template>
script部分
- <script setup>
- import { ref, onMounted } from 'vue' // 引入ref和onMounted
- import Sortable from 'sortablejs'
- const roleList = ref([
- {partName: 1,
- batchNo:2,
- invoiceNo: 3,
- orderNo:4,
- boxNo: 5,
- caseNo: 6,}
- ]);
- const dropCol = ref([
- {
- label: '零件名称',
- prop: 'partName',
- status:true
- },
- {
- label: '批次号',
- prop: 'batchNo',
- status:true
- },
- {
- label: '发票号',
- prop: 'invoiceNo',
- status:true
- },
- {
- label: '订单号',
- prop: 'orderNo',
- status:true
- },
- {
- label: '箱号',
- prop: 'boxNo',
- status:true
- },
- {
- label: '小箱号',
- prop: 'caseNo',
- status:true
- }
- ])
- const Col = ref([
- {
- label: '零件名称',
- prop: 'partName',
- status:true
- },
- {
- label: '批次号',
- prop: 'batchNo',
- status:true
- },
- {
- label: '发票号',
- prop: 'invoiceNo',
- status:true
- },
- {
- label: '订单号',
- prop: 'orderNo',
- status:true
- },
- {
- label: '箱号',
- prop: 'boxNo',
- status:true
- },
- {
- label: '小箱号',
- prop: 'caseNo',
- status:true
- }
- ])
- let checkAll = ref(true)
- function handleCheckAllChange() {
- dropCol.value.forEach(item => {
- item.status = checkAll.value;
- });
- }
- function handleCheckedBoxChange() {
- const allTrue = dropCol.value.every(item => item.status === true);
- Col.value=dropCol.value.filter(item=>item.status==true)
- console.log(Col.value);
- if (allTrue) {
- checkAll.value = true
- } else {
- checkAll.value = false
- }
-
- }
-
- //列拖拽
- function columnDrop() {
- const wrapperTr = document.querySelector('.el-table__header-wrapper tr')
- console.log(wrapperTr);
- Sortable.create(wrapperTr, {
- animation: 180,
- delay: 0,
- onEnd: evt => {
- // 过滤掉dropCol为false的项
- const oldItem = Col.value[evt.oldIndex];
- Col.value.splice(evt.oldIndex, 1);
- Col.value.splice(evt.newIndex, 0, oldItem);
- console.log(evt.oldIndex,evt.newIndex);
-
- }
- })
- }
-
- // 自适应表格列宽
- const flexColumnWidth = (str, tableData, flag = 'max') => {
- // str为该列的字段名(传字符串);tableData为该表格的数据源(传变量);
- // flag为可选值,可不传该参数,传参时可选'max'或'equal',默认为'max'
- // flag为'max'则设置列宽适配该列中最长的内容,flag为'equal'则设置列宽适配该列中第一行内容的长度。
-
- str = str + ''
- let columnContent = ''
- if (!tableData || !tableData.length || tableData.length === 0 || tableData === undefined) {
- return
- }
- if (!str || !str.length || str.length === 0 || str === undefined) {
- return
- }
-
- if (flag === 'equal') {
- // 获取该列中第一个不为空的数据(内容)
- for (let i = 0; i < tableData.length; i++) {
- if (tableData[i][str].length > 0) {
- // console.log('该列数据[0]:', tableData[0][str])
- columnContent = tableData[i][str]
- break
- }
- }
- } else {
- // 获取该列中最长的数据(内容)
- let index = 0
- for (let i = 0; i < tableData.length; i++) {
- // 数据为空跳出循环
- // if (tableData[i][str] === null) {
- // return
- // }
- const now_temp = tableData[i][str] + ''
- const max_temp = tableData[index][str] + ''
- if (now_temp.length > max_temp.length) {
- index = i
- }
- }
- columnContent = tableData[index][str]
- }
- // console.log('该列数据[i]:', columnContent)
- // 以下分配的单位长度可根据实际需求进行调整
- let flexWidth = 0
- columnContent = columnContent + ''
- for (const char of columnContent) {
- if ((char >= 'A' && char <= 'Z') || (char >= 'a' && char <= 'z')) {
- // 如果是英文字符,为字符分配8个单位宽度
- flexWidth += 12
- } else if (char >= '\u4e00' && char <= '\u9fa5') {
- // 如果是中文字符,为字符分配15个单位宽度
- flexWidth += 15
- } else {
- // 其他种类字符,为字符分配15个单位宽度
- flexWidth += 12
- }
- }
- if (flexWidth < 80) {
- // 设置最小宽度
- flexWidth = 80
- }
- // if (flexWidth > 250) {
- // // 设置最大宽度
- // flexWidth = 250
- // }
- return flexWidth + 'px'
- }
- // 自定义汇总方法
- const getSummaries = (param) => {
- const { columns, data } = param
- const sums = []
- columns.forEach((column, index) => {
- if (index === 0) {
- sums[index] = '总数'
- return
- }
- // console.log(column.property);
- // 将所有元素的值转换成数字类型
- const values = data.map((item) => Number(item[column.property]))
- // console.log(values.some((val) => Number.isNaN(val)));
- // every 只要有一个是数字,就会返回true
- // 判断数组中的数据是否是数字类型 some 只要存在一个是NaN那么就返回false
- if (!values.some((value) => Number.isNaN(value))) {
- sums[index] = ` ${values.reduce((prev, curr) => {
- const value = Number(curr)
- if (!Number.isNaN(value)) {
- return prev + curr
- } else {
- return prev
-
- }
- }, 0)}`
- } else {
- sums[index] = '/'
- }
- })
-
- return sums
- }
-
-
- onMounted(() => {
- columnDrop()
- })
- </script>
封装的代码在这篇文章
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。