项目场景:
vue3+element-plus
这里是点击按钮出现选择品牌的弹窗,且原有数据不能编辑,只有新增的可以删除 效果图如下:
1、原有数据回显
2、新增数据可以删除
解决方案
每次更新table数据时先去除所有的选中状态,然后筛选出本页数据已经选中的给与选中状态
请注意:重要方法 refreshDeleteRowSelection
、 rowClick
、rowSelect
1、父组件引用,选择品牌弹窗使用popover 主要代码如下:
<el-popover
v-if="!isRead"
:ref="
(el) =>
setRefItem({
el,
key: 'popover',
index: scope.$index,
})
"
placement="right"
:width="620"
trigger="click"
@before-enter="handleShowBrandPopover(scope.$index)"
@hide="handleHide"
>
<template #reference>
<div class="brand">
<div
v-if="!isRead"
class="btn flex flex-align-center"
:class="scope.row[rowBrandKey]?.length === 0 ? 'no-line' : ''"
>
<el-button class="btn-brand" link :dark="true">+选择品牌</el-button>
</div>
<div class="value">
<span
v-for="(item, index) in scope.row[rowBrandKey]"
:key="item.brandCode"
:class="showMark && !item.disabled ? 'text-red' : ''"
>{{ item.brandName
}}{{ index < scope.row[rowBrandKey].length - 1 ? '、' : '' }}</span
>
</div>
</div>
</template>
<select-pop
:ref="
(el) =>
setRefItem({
el,
key: 'selectBrand',
index: scope.$index,
})
"
:checked="scope.row[rowBrandKey]"
@close="handleCloseBrandPopover(scope.$index)"
@submit="(data) => handleSubmitBrandPopover(scope.row, scope.$index, data)"
></select-pop>
</el-popover>
import selectPop from './select-pop.vue';
//...
const popoverRefMap = ref({});
const selectBrandRefMap = ref({});
const setRefItem = ({ el, key, index }) => {
if (key === 'popover') {
popoverRefMap.value[`${key}${index}Ref`] = el;
} else if (key === 'selectBrand') {
selectBrandRefMap.value[`${key}${index}Ref`] = el;
}
};
const handleCloseBrandPopover = (index) => {
popoverRefMap.value[`popover${index}Ref`].hide();
};
const handleSubmitBrandPopover = (row, index, data) => {
row[$props.rowBrandKey] = data;
$emits('update', { row, index, value: data });
handleCloseBrandPopover(index);
};
const handleShowBrandPopover = (index) => {
$emits('show');
selectBrandRefMap.value[`selectBrand${index}Ref`].resetData();
// 重置
};
2、子组件即选择品牌弹窗,主要代码如下:
<div>
<div class="box1">
<el-input
placeholder="搜索品牌"
v-model="params.brandName"
@change="handleSearchChange"
></el-input>
<el-button text class="btn" @click="handleSearchChange">
<el-icon color="#999999" :size="18"><Search /></el-icon>
</el-button>
</div>
<div class="box2">
<div class="list">
<sc-table
ref="tableRef"
rowKey="brandCode"
:data="data"
:head="head"
:load="loading"
:page="pages"
:border="false"
:show-header="false"
:stripe="false"
:table-height="410"
:selection="true"
:reserveSelection="true"
:selectable="selectable"
:cellStyle="{
'border-bottom': '1px solid #e5e5e5',
cursor: 'pointer',
}"
:selectionWidth="28"
@reload="reload"
@pageChange="pageChange"
@select="rowSelect"
@rowClick="rowClick"
></sc-table>
</div>
<div class="selected flex flex-column">
<div class="title">
<div class="txt">已选品牌</div>
<el-button text class="btn" @click="handleDeleteAll">
<el-icon color="#666666" :size="15"><Delete /></el-icon>
</el-button>
</div>
<div class="selected-info flex-1">
<el-tag
v-for="item in checkList"
:key="item.brandCode"
type="info"
:closable="item.disabled ? false : true"
@close="handleDelete(item)"
>{{ item.brandName }}</el-tag
>
</div>
<div class="btns">
<el-button size="small" @click="handleClosePopover">取消</el-button>
<el-button size="small" type="primary" @click="handleSubmitPopover"
>提交</el-button
>
</div>
</div>
</div>
</div>
import { getProductBrandList } from '@/api/scm/suppler/baseconf';
import useTable from '@/hooks/use-table.js';
const $emits = defineEmits(['close', 'submit']);
const $props = defineProps({
checked: {
type: Array,
default() {
return [];
},
},
});
const head = ref([
{
name: '品牌',
key: 'brandName',
},
]);
const selectable = row => {
return row.disabled ? false : true;
};
const { data, pages, loading, params, queryAsyncFu } = useTable();
params.value = {
brandName: '',
};
const checkList = ref(JSON.parse(JSON.stringify($props.checked)));
//检索
const handleSearchChange = async val => {
pages.value.index = 1;
data.value = [];
await queryAsyncFu(getProductBrandList, filterData);
refreshDeleteRowSelection(data.value);
};
const reload = () => {
queryAsyncFu(getProductBrandList, filterData);
};
const filterData = val => {
const disabledBrandCodeArr = $props.checked.map(item => {
if (item.disabled) {
return item.brandCode;
}
});
for (let item of val) {
if (disabledBrandCodeArr.includes(item.brandCode)) {
item.disabled = true;
}
}
return val;
};
const pageChange = async val => {
pages.value.index = val;
data.value = [];
await queryAsyncFu(getProductBrandList, filterData);
refreshDeleteRowSelection(data.value);
};
const rowClick = data => {
if (data.disabled) {
return;
}
let val = true;
if (checkList.value.some(item => item.brandCode === data.brandCode)) {
val = false;
}
tableRef.value.toggleRowSelection(data, val);
const selected = tableRef.value.getSelectionRows();
rowSelect(selected);
};
const rowSelect = val => {
// 如果初始化列表中有被选中的不可编辑的选项 不在val值里 则需要补上 比如不在当前列表里的数据
const disabledCheckedList = checkList.value.filter(brand => brand.disabled);
const arr = [];
disabledCheckedList.forEach(item => {
if (!val.some(brand => brand.brandCode === item.brandCode)) {
arr.push(item);
}
});
val = arr.concat(val);
checkList.value = val;
};
// 删除的项不在当前页时 去掉左侧table某项的选中状态
const refreshDeleteRowSelection = data => {
nextTick(() => {
const checkedBrandCodeArr = checkList.value.map(item => item.brandCode);
data.forEach(item => {
if (!checkedBrandCodeArr.includes(item.brandCode)) {
tableRef.value.toggleRowSelection(item, false);
} else {
tableRef.value.toggleRowSelection(item, true);
}
});
});
};
const toggleRowSelection = (data, brandCode, isChecked) => {
const tableItem = data.find(brand => brand.brandCode === brandCode);
tableItem && tableRef.value.toggleRowSelection(tableItem, isChecked || false);
};
const handleDelete = item => {
if (item.disabled) {
return;
}
const deleteIndex = checkList.value.findIndex(brand => brand.brandCode === item.brandCode);
toggleRowSelection(data.value, item.brandCode, false);
checkList.value.splice(deleteIndex, 1);
};
const tableRef = ref(null);
const handleDeleteAll = () => {
tableRef.value.clearSelection();
const disabledCheckedList = checkList.value.filter(brand => brand.disabled);
disabledCheckedList.forEach(item => {
toggleRowSelection(data.value, item.brandCode, true);
});
checkList.value = checkList.value.filter(brand => brand.disabled);
};
const resetData = async () => {
params.value = {
brandName: '',
};
pages.value = {
size: 20,
count: 0,
index: 1,
lastPage: 1,
};
data.value = [];
await queryAsyncFu(getProductBrandList, filterData);
checkList.value = JSON.parse(JSON.stringify($props.checked));
tableRef.value.clearSelection();
if (checkList.value.length) {
checkList.value.forEach(item => {
toggleRowSelection(data.value, item.brandCode, true);
});
}
};
const handleClosePopover = () => {
$emits('close');
};
const handleSubmitPopover = () => {
for (let item of checkList.value) {
if (!item.disabled) {
item.isAdd = true;
}
}
$emits('submit', checkList.value);
};
defineExpose({
resetData,
});