vxe-table编辑单元格动态插槽slot的使用

业务场景:表格中只有特定某一行的的单元格可以编辑,列很多,为每个列写个插槽要写很多重复代码,所以这里使用动态插槽,简化代码量。显示编辑图标,点击编辑图标隐藏。失去焦点保存调后台接口。

解决办法:

1、后端返回的数据里可以编辑的行数据添加属性 edit: true;不可编辑的行数据里添加属性 edit: false;

2、把列数组里的插槽和field提取出来为循环使用做准备,如果直接使用导入进来的columns无法显示,所以需要处理后使用。
列名文件示例columns.js

javascript 复制代码
export const columns1 = [
  {
    title: '名称',
    field: "heatSourceName",
    align: 'left',
    width: "160",
    slots: { header: 'header_heatSourceName', default: '_heatSourceName' },
  },
  {
    title: "日流量(t/h)",
    field: "supTemp",
    width: "140",
    align: 'right',
    sortable: false,
    editRender: { autofocus: '.vxe-input--inner' },
    slots: { default: '_supTemp', edit: 'edit_supTemp' },
  },
  {
    title: "日热量(GJ/h)",
    field: "supPres",
    width: "140",
    align: 'right',
    sortable: false,
    editRender: { autofocus: '.vxe-input--inner' },
    slots: { default: '_supPres', edit: 'edit_supPres' },
  },
  {
    title: "日压力(Mpa)",
    field: "instFlowSup",
    width: "160",
    align: 'right',
    sortable: false,
    editRender: { autofocus: '.vxe-input--inner' },
    slots: { default: '_instFlowSup', edit: 'edit_instFlowSup' },
  }, ...]

HTML写法

html 复制代码
<vxe-grid ref="xGrid1" v-bind="gridOptions1" :span-method="spanMethods">
                <template #header_heatSourceName>
                  <div class="first-col">
                    <div class="first-col-top">指标</div>
                    <div class="first-col-bottom">热源</div>
                  </div>
                </template>
                <!--  分割线,动态插槽写法   -->
                <template v-for="item in defaultSlots1" :key="item.field" v-slot:[item.slot]="{ row }">
                  <div style="display: flex; align-items: center;`justify-content: ${row[item.field] === 'heatSourceName' ? flex-start : flex-end}`"
                    v-if="row.edit && timeInfo === timeInfo1">
                    <i class="vxe-cell--edit-icon vxe-icon-edit" style="margin-right: 5px;"></i>{{ row[item.field] }}
                  </div>
                  <div v-else>
                    {{ row[item.field] }}
                  </div>
                </template>
                <template v-for="item in editSlots1" :key="item.field" v-slot:[item.slot]="{ row }">
                  <div v-if="row.edit && timeInfo === timeInfo1">
                    <vxe-input v-model="row[item.field]" type="number" :min="0" :max="99999999"></vxe-input>
                  </div>
                  <div v-else>
                    {{ row[item.field] }}
                  </div>
                </template>
                <!--  分割线,下面为常规写法   -->
                <!-- <template #_supTemp="{ row }">
                  <div style="display: flex; align-items: center;justify-content: flex-end;"
                    v-if="row.edit && timeInfo === timeInfo1">
                    <i class="vxe-cell--edit-icon vxe-icon-edit" style="margin-right: 5px;"></i>{{ row.supTemp }}
                  </div>
                  <div v-else>
                    {{ row.supTemp }}
                  </div>
                </template>
                <template #edit_supTemp="{ row }">
                  <div v-if="row.edit && timeInfo === timeInfo1">
                    <vxe-input v-model="row.supTemp" type="number" :min="0" :max="99999999"></vxe-input>
                  </div>
                  <div v-else>
                    {{ row.supTemp }}
                  </div>
                </template>
                <template #_supPres="{ row }">
                  <div style="display: flex; align-items: center;justify-content: flex-end;"
                    v-if="row.edit && timeInfo === timeInfo1">
                    <i class="vxe-cell--edit-icon vxe-icon-edit" style="margin-right: 5px;"></i>{{ row.supPres }}
                  </div>
                  <div v-else>
                    {{ row.supPres }}
                  </div>
                </template>
                <template #edit_supPres="{ row }">
                  <div v-if="row.edit && timeInfo === timeInfo1">
                    <vxe-input v-model="row.supPres" type="number" :min="0" :max="99999999"></vxe-input>
                  </div>
                  <div v-else>
                    {{ row.supPres }}
                  </div>
                </template>
                <template #_waterCnp="{ row }">
                  <div style="display: flex; align-items: center;justify-content: flex-end;"
                    v-if="row.edit && timeInfo === timeInfo1">
                    <i class="vxe-cell--edit-icon vxe-icon-edit" style="margin-right: 5px;"></i>{{ row.waterCnp }}
                  </div>
                  <div v-else>
                    {{ row.waterCnp }}
                  </div>
                </template>
                <template #edit_waterCnp="{ row }">
                  <div v-if="row.edit && timeInfo === timeInfo1">
                    <vxe-input v-model="row.waterCnp" type="number" :min="0" :max="99999999"></vxe-input>
                  </div>
                  <div v-else>
                    {{ row.waterCnp }}
                  </div>
                </template> -->
              </vxe-grid>

Js写法

javascript 复制代码
<script>
import {
  defineComponent,
  ref,
  reactive,
  toRefs,
  computed,
  watch,
  onMounted,
  nextTick,
} from 'vue'
import { columns1 } from './columns.js';
import moment from 'moment'
import { useAppStoreWithOut } from '@/store/modules/app'

export default defineComponent({
  setup() {
    const appStore = useAppStoreWithOut();
    const state = reactive({
      timeInfo: moment(appStore.getSysTime).subtract(1, 'day').format('YYYY年MM月DD日'),
      timeInfo1: moment(appStore.getSysTime).subtract(1, 'day').format('YYYY年MM月DD日'),
      gridOptions1: {
        border: true,
        height: '100%',
        showFooter: false,
        showOverflow: true,
        'column-config': { resizable: false },
        'edit-config': {
          trigger: 'click', mode: 'cell', showIcon: false },
        'scroll-y': { enable: true, mode: 'wheel' },
        columns: computed(() => {
          // 拼接序号列
          return columns1;
        }),
        data: computed(() => {
          let data = [
            {
              "heatSourceName": "Leo源",
              "supTemp": null,
              "supPres": null,
              "instFlowSup": null,
              "retTemp": null,
              "retPres": null,
              "muwInstFlow": null,
              "heatCnp": null,
              "waterCnp": null,
              "muwaccFlow": null,
              "accHeat": null
            },
            {
              "heatSourceName": "晋源",
              "supTemp": "86.89",
              "supPres": null,
              "instFlowSup": "1028.31",
              "retTemp": "41.51",
              "retPres": "0.111",
              "muwInstFlow": "514.64",
              "heatCnp": "7923.92",
              "waterCnp": "396.58",
              "muwaccFlow": "29207293.83",
              "accHeat": "680.0334"
            },
            {
              "heatSourceName": "龙山",
              "supTemp": "86.90",
              "supPres": null,
              "instFlowSup": "514.24",
              "retTemp": "41.50",
              "retPres": null,
              "muwInstFlow": "515.29",
              "heatCnp": "3960.97",
              "waterCnp": "395.64",
              "muwaccFlow": "1148264.05",
              "accHeat": "166.2449"
            }
          ]
          data.forEach((item, index) => {
            if (index === 1 || index === 2) {
              item.edit = true
            } else {
              item.edit = false
            }
          });
          return data
        }),
      },
      // 合并单元格方法,这里只合并第一行和第二行
      spanMethods({ row, $rowIndex, column, data }) {
        let fields = ["retTemp"]
        let cellValue = row[column.property]
        if ($rowIndex == 2 || $rowIndex == 3) {
          if (cellValue && fields.includes(column.property)) {
            let prevRow = data[$rowIndex - 1]
            let nextRow = data[$rowIndex + 1]

            if (prevRow && prevRow[column.property] === cellValue) {
              return { rowspan: 0, colspan: 0 }
            } else {
              let countRowspan = 1
              while (nextRow && nextRow[column.property] === cellValue) {
                nextRow = data[++countRowspan + $rowIndex]
              }
              if (countRowspan > 1) {
                return { rowspan: countRowspan, colspan: 1 }
              }
            }
          }
        }
    })
    
    // 提取默认插槽
    const defaultSlots1 = computed(() => {
      return columns1.map((column, index) => {
        return {
          slot: column.slots.default,
          field: column.field,
        }
      })
    })
    // 提取编辑插槽
    const editSlots1 = computed(() => {
      return columns1.map((column, index) => {
        return {
          slot: column.slots.edit,
          field: column.field
        }
      })
    })
   }
 
    
    return {
      ...toRefs(state),   
      defaultSlots1,
      editSlots1,
    }
  },

})
</script>
相关推荐
谢道韫6667 分钟前
今日总结 2024-12-24
javascript·vue.js·elementui
一朵好运莲8 分钟前
React引入Echart水球图
开发语言·javascript·ecmascript
米奇妙妙wuu14 分钟前
react使用sse流实现chat大模型问答,补充css样式
前端·css·react.js
傻小胖19 分钟前
React 生命周期完整指南
前端·react.js
梦境之冢1 小时前
axios 常见的content-type、responseType有哪些?
前端·javascript·http
racerun1 小时前
vue VueResource & axios
前端·javascript·vue.js
J总裁的小芒果1 小时前
THREE.js 入门(六) 纹理、uv坐标
开发语言·javascript·uv
m0_548514771 小时前
前端Pako.js 压缩解压库 与 Java 的 zlib 压缩与解压 的互通实现
java·前端·javascript
AndrewPerfect1 小时前
xss csrf怎么预防?
前端·xss·csrf
Calm5501 小时前
Vue3:uv-upload图片上传
前端·vue.js