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

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

方法一、

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

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

方法二、可以为每个列名使用相同的插槽名,使代码更简洁。

列名文件示例columns.js

 export const columns2 = [{
    title: '温差',
    field: 'pumpCon',
    align: 'center',
    width: "160",
    editRender: {},
    slots: { 
      edit: 'input_edit',
      default: 'input_default',
    },
  },
  {
    title: '昨日水',
    field: 'yesterdayWater',
    align: 'right',
    width: "110",
    editRender: {},
    slots: { 
      edit: 'input_edit',
      default: 'input_default',
    },
  },
  {
    title: '累计',
    field: 'yesterdayWaterSum',
    align: 'right',
    width: "110",
  },
]
 <!-- input_edit -->
              <template #input_edit="{ row, rowIndex, $rowIndex, column, columnIndex, $columnIndex, _columnIndex }">

                <!-- number -->
                <div
                  v-if="[1].includes(rowIndex) && ['pumpCon'].includes(column.field)"
                  style="display: flex; align-items: center;justify-content: flex-end;"
                >
                  <vxe-input
                    v-model="row[column.field]"
                    type="float"
                    :min="0"
                    :max="99999999"
                    :digits="getDigits(column.title)"
                    @prev-number="onClickBtn(row, rowIndex, column.field, time)"
                    @next-number="onClickBtn(row, rowIndex, column.field, time)"
                    @blur="onBlur(row, rowIndex, column.field, time)"
                  ></vxe-input>
                </div>

                <!-- else -->
                <div v-else>
                  {{ row[column.field] }}
                </div>

              </template>

// Js代码 这里失去焦点就调接口,所以当使用输入框的上下箭头时,加入防抖使用
     // 防抖
      onClickBtn: debounce((row, rowIndex, field, time)=>{
        methods.onBlur(row, rowIndex, field, time);
      }, 300),
      onBlur(row, rowIndex, field, time) {
        let value = row?.[field] || '';
        let key = `${rowIndex}-${field}`;
        ...  
      }

方法一、列名文件示例columns.js

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写法

<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写法

<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>

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值