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