el-table中分页 el-checkbox 多选回显、选中和删除

项目场景:

vue3+element-plus

这里是点击按钮出现选择品牌的弹窗,且原有数据不能编辑,只有新增的可以删除 效果图如下:
1、原有数据回显
在这里插入图片描述
2、新增数据可以删除
在这里插入图片描述


解决方案

每次更新table数据时先去除所有的选中状态,然后筛选出本页数据已经选中的给与选中状态

请注意:重要方法 refreshDeleteRowSelectionrowClickrowSelect

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,
});

### 禁用 Element UI `el-table` 组件中的 Checkbox功能 为了实现在 `el-table` 中禁用全的功能,可以采用种方式来满足特定需求。 #### 方法一:自定义表头并设置全框为禁用状态 通过重写默认的表头模板,在其中放置一个被禁用的复框,从而阻止用户的全操作。这种方式简单直观: ```html <el-table :border="true" :data="tableData"> <el-table-column width="50" align="center"> <!-- 自定义表头 --> <template slot="header"> <el-checkbox disabled /> </template> <!-- 行内复框保持可用 --> <template slot-scope="scope"> <el-checkbox v-model="scope.row.checked"/> </template> </el-table-column> </el-table> ``` 这种方法适用于只需要简单的禁用全而不涉及复杂逻辑的情况[^2]。 #### 方法二:基于数据条件动态控制全按钮的状态 如果希望更灵活地管理何时允许或不允许全,则可以在表格上监听事件,并根据业务规则调整全行为。例如,当所有行都被标记为不可编辑时自动关闭全项;反之则开启它。具体做法如下所示: 1. 使用 `header-cell-class-name` 属性绑定到一个函数; 2. 在该函数内部判断是否应该应用特殊样式(比如 'all-disabled'),这取决于是否有任何记录处于可选中状态; 3. 利用 CSS 来隐藏或改变外观以反映实际状态。 ```css .all-disabled .cell { color: gray; } ``` 此方法提供了更大的灵活性,可以根据不同的应用场景定制化处理策略[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值