当前位置:   article > 正文

elemetui自定义表格实现可拖拽列、显示隐藏列、数据汇总、自适应宽度_elementui表格宽度拖动

elementui表格宽度拖动

效果如下:

elemetui自定义表格实现可拖拽列、显示隐藏列、数据汇总、自适应宽度

1.可拖拽列

使用前需要先安装一个包

npm i -S vuedraggable

使用的时候需要注意几个地方:

第一个是必须设置row-key,你的值必须是唯一值,不一定是id也可以是其他的

第二个是你需要设置两个对象:Col和dropCol,这两个对象是保存每一列的label和prop的,虽然这两个是一样的,但是必须要设置两个,否则就会导致你拖拽替换只会替换每一列对应的值不会替换label。对象形式如下:

  1. const Col = ref([
  2. {
  3. label: '零件名称',
  4. prop: 'partName',
  5. status:true
  6. },
  7. {
  8. label: '批次号',
  9. prop: 'batchNo',
  10. status:true
  11. },
  12. {
  13. label: '发票号',
  14. prop: 'invoiceNo',
  15. status:true
  16. },
  17. {
  18. label: '订单号',
  19. prop: 'orderNo',
  20. status:true
  21. },
  22. {
  23. label: '箱号',
  24. prop: 'boxNo',
  25. status:true
  26. },
  27. {
  28. label: '小箱号',
  29. prop: 'caseNo',
  30. status:true
  31. }
  32. ])
  1. <el-table :data="roleList" show-summary row-key="id"
  2. :summary-method="getSummaries">
  3. <template v-for="(col,index) in Col" :key="index" >
  4. <el-table-column :width="index==0? flexColumnWidth(col.prop, roleList):'300'"
  5. :label="col.label" :prop="col.prop" align="center" />
  6. </template>
  7. </el-table>

然后下面是列拖拽的方法

  1. //列拖拽
  2. function columnDrop() {
  3. const wrapperTr = document.querySelector('.el-table__header-wrapper tr')
  4. Sortable.create(wrapperTr, {
  5. animation: 180,
  6. delay: 0,
  7. onEnd: evt => {
  8. // 过滤掉dropCol为false的项
  9. const oldItem = Col.value[evt.oldIndex];
  10. Col.value.splice(evt.oldIndex, 1);
  11. Col.value.splice(evt.newIndex, 0, oldItem);
  12. console.log(evt.oldIndex,evt.newIndex);
  13. }
  14. })
  15. }
  16. //需要在onMouted函数中调用一次
  17. onMounted(() => {
  18. columnDrop()
  19. })

2.自定义列宽

给每一列添加这个代码

:width="flexColumnWidth(dropCol[1].prop, tableData)"

如果只是想在某一列添加可以这样,宽度自定义

:width="index==0? flexColumnWidth(col.prop, roleList):'300'"

方法如下:

注意如果那一列的数据存在某一个是空值那么那一项就会不进入自适应宽度,把下面的注释掉就可以了;

  1. // 自适应表格列宽
  2. const flexColumnWidth = (str, tableData, flag = 'max') => {
  3. // str为该列的字段名(传字符串);tableData为该表格的数据源(传变量);
  4. // flag为可选值,可不传该参数,传参时可选'max''equal',默认为'max'
  5. // flag为'max'则设置列宽适配该列中最长的内容,flag为'equal'则设置列宽适配该列中第一行内容的长度。
  6. str = str + ''
  7. let columnContent = ''
  8. if (!tableData || !tableData.length || tableData.length === 0 || tableData === undefined) {
  9. return
  10. }
  11. if (!str || !str.length || str.length === 0 || str === undefined) {
  12. return
  13. }
  14. if (flag === 'equal') {
  15. // 获取该列中第一个不为空的数据(内容)
  16. for (let i = 0; i < tableData.length; i++) {
  17. if (tableData[i][str].length > 0) {
  18. // console.log('该列数据[0]:', tableData[0][str])
  19. columnContent = tableData[i][str]
  20. break
  21. }
  22. }
  23. } else {
  24. // 获取该列中最长的数据(内容)
  25. let index = 0
  26. for (let i = 0; i < tableData.length; i++) {
  27. // 数据为空跳出循环
  28. // if (tableData[i][str] === null) {
  29. // return
  30. // }
  31. const now_temp = tableData[i][str] + ''
  32. const max_temp = tableData[index][str] + ''
  33. if (now_temp.length > max_temp.length) {
  34. index = i
  35. }
  36. }
  37. columnContent = tableData[index][str]
  38. }
  39. // console.log('该列数据[i]:', columnContent)
  40. // 以下分配的单位长度可根据实际需求进行调整
  41. let flexWidth = 0
  42. columnContent = columnContent + ''
  43. for (const char of columnContent) {
  44. if ((char >= 'A' && char <= 'Z') || (char >= 'a' && char <= 'z')) {
  45. // 如果是英文字符,为字符分配8个单位宽度
  46. flexWidth += 12
  47. } else if (char >= '\u4e00' && char <= '\u9fa5') {
  48. // 如果是中文字符,为字符分配15个单位宽度
  49. flexWidth += 15
  50. } else {
  51. // 其他种类字符,为字符分配15个单位宽度
  52. flexWidth += 12
  53. }
  54. }
  55. if (flexWidth < 80) {
  56. // 设置最小宽度
  57. flexWidth = 80
  58. }
  59. // if (flexWidth > 250) {
  60. // // 设置最大宽度
  61. // flexWidth = 250
  62. // }
  63. return flexWidth + 'px'
  64. }

3.显示隐藏列

通过v-if命令动态修改你每一列是否显示

设置一个对象,包含你每一列的项

  1. const dropCol = ref([
  2. {
  3. label: '零件名称',
  4. prop: 'partName',
  5. status:true
  6. },
  7. {
  8. label: '批次号',
  9. prop: 'batchNo',
  10. status:true
  11. },
  12. {
  13. label: '发票号',
  14. prop: 'invoiceNo',
  15. status:true
  16. },
  17. {
  18. label: '订单号',
  19. prop: 'orderNo',
  20. status:true
  21. },
  22. {
  23. label: '箱号',
  24. prop: 'boxNo',
  25. status:true
  26. },
  27. {
  28. label: '小箱号',
  29. prop: 'caseNo',
  30. status:true
  31. }
  32. ])

控制列的面板:el-popover是一个弹框,然后里面自定义多选框内容

  1. <el-popover placement="bottom-start" :width="600" trigger="hover">
  2. <transition name="fade">
  3. <div>
  4. <div>选择需要显示的列</div>
  5. <div>
  6. <el-checkbox v-model="checkAll" @change="handleCheckAllChange">全选</el-checkbox>
  7. <el-checkbox v-for="(item, index) in dropCol" :key="index" @change="handleCheckedBoxChange" v-model="item.status">{{item.label}}</el-checkbox>
  8. </div>
  9. </div>
  10. </transition>
  11. <template #reference>
  12. <el-button icon="Setting">显示列</el-button>
  13. </template>
  14. </el-popover>

全选和复选的方法

  1. function handleCheckAllChange() {
  2. dropCol.value.forEach(item => {
  3. item.status = checkAll.value;
  4. });
  5. }
  6. function handleCheckedBoxChange() {
  7. const allTrue = dropCol.value.every(item => item.status === true);
  8. Col.value=dropCol.value.filter(item=>item.status==true)
  9. if (allTrue) {
  10. checkAll.value = true
  11. } else {
  12. checkAll.value = false
  13. }
  14. }

4.自定义汇总

表格需要添加show-summary   :summary-method="getSummaries"

<el-table :data="roleList" show-summary :summary-method="getSummaries">

方法如下:

  1. // 自定义汇总方法
  2. const getSummaries = (param) => {
  3. const { columns, data } = param
  4. const sums = []
  5. columns.forEach((column, index) => {
  6. if (index === 0) {
  7. sums[index] = '总数'
  8. return
  9. }
  10. console.log(column.property);
  11. // 将所有元素的值转换成数字类型
  12. const values = data.map((item) => Number(item[column.property]))
  13. console.log(values.some((val) => Number.isNaN(val)));
  14. // every 只要有一个是数字,就会返回true
  15. // 判断数组中的数据是否是数字类型 some 只要存在一个是NaN那么就返回false
  16. if (!values.some((value) => Number.isNaN(value))) {
  17. sums[index] = ` ${values.reduce((prev, curr) => {
  18. const value = Number(curr)
  19. if (!Number.isNaN(value)) {
  20. return prev + curr
  21. } else {
  22. return prev
  23. }
  24. }, 0)}`
  25. } else {
  26. sums[index] = '/'
  27. }
  28. })
  29. return sums
  30. }

如果想要把合计行放到顶部去,可以使用css样式修改。

  1. /* order默认值为0,只需将表体order置为1即可移到最后,这样合计行就上移到表体上方 */
  2. ::v-deep .el-table__body-wrapper {
  3. order: 1;
  4. }
  5. ::v-deep .el-table__fixed-body-wrapper {
  6. top: 96px !important;
  7. }
  8. ::v-deep .el-table__fixed-footer-wrapper {
  9. z-index: 0;
  10. }

5.所有功能汇总表格

template部分

  1. <template>
  2. <div>
  3. <el-popover placement="bottom-start" :width="600" trigger="hover">
  4. <transition name="fade">
  5. <div>
  6. <div>选择需要显示的列</div>
  7. <div>
  8. <el-checkbox v-model="checkAll" @change="handleCheckAllChange">全选</el-checkbox>
  9. <el-checkbox v-for="(item, index) in dropCol" :key="index" @change="handleCheckedBoxChange" v-model="item.status">{{item.label}}</el-checkbox>
  10. </div>
  11. </div>
  12. </transition>
  13. <template #reference>
  14. <el-button icon="Setting">显示列</el-button>
  15. </template>
  16. </el-popover>
  17. <el-table :data="roleList" show-summary row-key="id"
  18. :summary-method="getSummaries">
  19. <template v-for="(col,index) in Col" :key="index" >
  20. <el-table-column :width="index==0? flexColumnWidth(col.prop, roleList):'300'"
  21. :label="col.label" :prop="col.prop" align="center" />
  22. </template>
  23. </el-table>
  24. </div>
  25. </template>

script部分

  1. <script setup>
  2. import { ref, onMounted } from 'vue' // 引入ref和onMounted
  3. import Sortable from 'sortablejs'
  4. const roleList = ref([
  5. {partName: 1,
  6. batchNo:2,
  7. invoiceNo: 3,
  8. orderNo:4,
  9. boxNo: 5,
  10. caseNo: 6,}
  11. ]);
  12. const dropCol = ref([
  13. {
  14. label: '零件名称',
  15. prop: 'partName',
  16. status:true
  17. },
  18. {
  19. label: '批次号',
  20. prop: 'batchNo',
  21. status:true
  22. },
  23. {
  24. label: '发票号',
  25. prop: 'invoiceNo',
  26. status:true
  27. },
  28. {
  29. label: '订单号',
  30. prop: 'orderNo',
  31. status:true
  32. },
  33. {
  34. label: '箱号',
  35. prop: 'boxNo',
  36. status:true
  37. },
  38. {
  39. label: '小箱号',
  40. prop: 'caseNo',
  41. status:true
  42. }
  43. ])
  44. const Col = ref([
  45. {
  46. label: '零件名称',
  47. prop: 'partName',
  48. status:true
  49. },
  50. {
  51. label: '批次号',
  52. prop: 'batchNo',
  53. status:true
  54. },
  55. {
  56. label: '发票号',
  57. prop: 'invoiceNo',
  58. status:true
  59. },
  60. {
  61. label: '订单号',
  62. prop: 'orderNo',
  63. status:true
  64. },
  65. {
  66. label: '箱号',
  67. prop: 'boxNo',
  68. status:true
  69. },
  70. {
  71. label: '小箱号',
  72. prop: 'caseNo',
  73. status:true
  74. }
  75. ])
  76. let checkAll = ref(true)
  77. function handleCheckAllChange() {
  78. dropCol.value.forEach(item => {
  79. item.status = checkAll.value;
  80. });
  81. }
  82. function handleCheckedBoxChange() {
  83. const allTrue = dropCol.value.every(item => item.status === true);
  84. Col.value=dropCol.value.filter(item=>item.status==true)
  85. console.log(Col.value);
  86. if (allTrue) {
  87. checkAll.value = true
  88. } else {
  89. checkAll.value = false
  90. }
  91. }
  92. //列拖拽
  93. function columnDrop() {
  94. const wrapperTr = document.querySelector('.el-table__header-wrapper tr')
  95. console.log(wrapperTr);
  96. Sortable.create(wrapperTr, {
  97. animation: 180,
  98. delay: 0,
  99. onEnd: evt => {
  100. // 过滤掉dropCol为false的项
  101. const oldItem = Col.value[evt.oldIndex];
  102. Col.value.splice(evt.oldIndex, 1);
  103. Col.value.splice(evt.newIndex, 0, oldItem);
  104. console.log(evt.oldIndex,evt.newIndex);
  105. }
  106. })
  107. }
  108. // 自适应表格列宽
  109. const flexColumnWidth = (str, tableData, flag = 'max') => {
  110. // str为该列的字段名(传字符串);tableData为该表格的数据源(传变量);
  111. // flag为可选值,可不传该参数,传参时可选'max''equal',默认为'max'
  112. // flag为'max'则设置列宽适配该列中最长的内容,flag为'equal'则设置列宽适配该列中第一行内容的长度。
  113. str = str + ''
  114. let columnContent = ''
  115. if (!tableData || !tableData.length || tableData.length === 0 || tableData === undefined) {
  116. return
  117. }
  118. if (!str || !str.length || str.length === 0 || str === undefined) {
  119. return
  120. }
  121. if (flag === 'equal') {
  122. // 获取该列中第一个不为空的数据(内容)
  123. for (let i = 0; i < tableData.length; i++) {
  124. if (tableData[i][str].length > 0) {
  125. // console.log('该列数据[0]:', tableData[0][str])
  126. columnContent = tableData[i][str]
  127. break
  128. }
  129. }
  130. } else {
  131. // 获取该列中最长的数据(内容)
  132. let index = 0
  133. for (let i = 0; i < tableData.length; i++) {
  134. // 数据为空跳出循环
  135. // if (tableData[i][str] === null) {
  136. // return
  137. // }
  138. const now_temp = tableData[i][str] + ''
  139. const max_temp = tableData[index][str] + ''
  140. if (now_temp.length > max_temp.length) {
  141. index = i
  142. }
  143. }
  144. columnContent = tableData[index][str]
  145. }
  146. // console.log('该列数据[i]:', columnContent)
  147. // 以下分配的单位长度可根据实际需求进行调整
  148. let flexWidth = 0
  149. columnContent = columnContent + ''
  150. for (const char of columnContent) {
  151. if ((char >= 'A' && char <= 'Z') || (char >= 'a' && char <= 'z')) {
  152. // 如果是英文字符,为字符分配8个单位宽度
  153. flexWidth += 12
  154. } else if (char >= '\u4e00' && char <= '\u9fa5') {
  155. // 如果是中文字符,为字符分配15个单位宽度
  156. flexWidth += 15
  157. } else {
  158. // 其他种类字符,为字符分配15个单位宽度
  159. flexWidth += 12
  160. }
  161. }
  162. if (flexWidth < 80) {
  163. // 设置最小宽度
  164. flexWidth = 80
  165. }
  166. // if (flexWidth > 250) {
  167. // // 设置最大宽度
  168. // flexWidth = 250
  169. // }
  170. return flexWidth + 'px'
  171. }
  172. // 自定义汇总方法
  173. const getSummaries = (param) => {
  174. const { columns, data } = param
  175. const sums = []
  176. columns.forEach((column, index) => {
  177. if (index === 0) {
  178. sums[index] = '总数'
  179. return
  180. }
  181. // console.log(column.property);
  182. // 将所有元素的值转换成数字类型
  183. const values = data.map((item) => Number(item[column.property]))
  184. // console.log(values.some((val) => Number.isNaN(val)));
  185. // every 只要有一个是数字,就会返回true
  186. // 判断数组中的数据是否是数字类型 some 只要存在一个是NaN那么就返回false
  187. if (!values.some((value) => Number.isNaN(value))) {
  188. sums[index] = ` ${values.reduce((prev, curr) => {
  189. const value = Number(curr)
  190. if (!Number.isNaN(value)) {
  191. return prev + curr
  192. } else {
  193. return prev
  194. }
  195. }, 0)}`
  196. } else {
  197. sums[index] = '/'
  198. }
  199. })
  200. return sums
  201. }
  202. onMounted(() => {
  203. columnDrop()
  204. })
  205. </script>

6.组件封装

封装的代码在这篇文章

封装elemetui自定义表格实现可拖拽列、显示隐藏列、数据汇总、自适应宽度组件-CSDN博客

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/420185
推荐阅读
相关标签
  

闽ICP备14008679号