单选:
html
<template>
<SelectMaterial
ref="selectMaterialRef"
check="checkbox"
@select="selectMaterial"
></SelectMaterial>
<el-button type="primary" size="small" icon="el-icon-plus" @click="handleAddMaterial"
>添加备件</el-button>
</template>
<script setup>
import { ref } from 'vue';
const selectMaterialRef = ref('');
// 选择事件
const selectMaterial = data => {
console.log('选择的表格数据', data);
};
// 打开添加备件弹框
const handleAddMaterial = () => {
selectMaterialRef.value.openDialog();
};
</script>
多选:
html
<template>
<SelectMaterial
ref="selectMaterialRef"
check="checkbox"
@select="selectMaterial"
></SelectMaterial>
<el-button type="primary" size="small" icon="el-icon-plus" @click="handleAddMaterial"
>添加备件</el-button>
</template>
<script setup>
import { ref } from 'vue';
const selectMaterialRef = ref('');
// 选择事件
const selectMaterial = data => {
console.log('选择的表格数据', data);
};
// 打开添加备件弹框
const handleAddMaterial = () => {
selectMaterialRef.value.openDialog();
};
</script>
弹框表格组件代码
html
<template>
<el-dialog v-model="dialogShow" @close="handleClose" width="50%" title="选择备件">
<el-table
border
ref="tableRef"
:data="tableData"
:row-key="row => row.id"
:header-cell-style="{ textAlign: 'center', backgroundColor: '#f3f3f3' }"
:cell-style="{ textAlign: 'center' }"
@selection-change="handleSelectionChange"
style="height: 352px; overflow: auto; margin: 10px 0"
size="small"
>
<el-table-column v-if="check === 'checkbox'" type="selection"></el-table-column>
<el-table-column v-else-if="check === 'radio'" width="50">
<template #default="scope">
<el-radio v-model="selectedRow" :value="scope.row.id"></el-radio>
</template>
</el-table-column>
<el-table-column type="index" width="80" label="序号">
<template #default="{ $index }">
{{ (currentPage - 1) * pageSize + $index + 1 }}
</template>
</el-table-column>
<el-table-column prop="partNumber" label="备件编号"></el-table-column>
<el-table-column prop="partName" label="备件名称"></el-table-column>
<el-table-column prop="specification" label="规格型号"></el-table-column>
<el-table-column prop="manufacturer" label="生产厂家"></el-table-column>
<el-table-column prop="unit" label="单位"></el-table-column>
</el-table>
<div style="display: flex; justify-content: flex-end; margin-top: 10px">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[10, 20, 30, 40]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
small
>
</el-pagination>
</div>
<div style="text-align: center; margin-top: 20px">
<el-button size="small" @click="handleClose" style="margin-right: 30px;">取消</el-button>
<el-button size="small" type="primary" @click="handleSelect">选择</el-button>
</div>
</el-dialog>
</template>
<script name="select-material-dialog" setup>
import { ref } from 'vue';
// 对话框是否可见
const dialogShow = ref(false);
// 多选选中的行
const selectedRows = ref([]);
// 单选选中的行
const selectedRow = ref(null);
// 当前页码
const currentPage = ref(1);
// 每页显示的条数
const pageSize = ref(10);
// 总条数
const total = ref(0);
// 表格数据
const tableData = ref([]);
// 表格ref
const tableRef = ref(null);
// 定义属性
const props = defineProps({
// 选择模式,可以是 'radio' 或 'checkbox'
check: {
type: String,
default: 'checkbox',
},
});
// 定义事件
const $emit = defineEmits(['select']);
// 获取数据的方法
const fetchData = async () => {
// 模拟接口请求,这里使用 setTimeout 来模拟异步操作
await new Promise(resolve => setTimeout(resolve, 1000));
// 更新数据
const data = Array.from({ length: pageSize.value }, (_, i) => ({
id: (currentPage.value - 1) * pageSize.value + i + 1, // 注意这里的 +1,因为 id 应该从 1 开始,而不是从 0 开始
partNumber: `编号${(currentPage.value - 1) * pageSize.value + i + 1}`, // 同样,编号也应该从 1 开始
partName: `名称${i}`,
specification: `规格${i}`,
manufacturer: `厂家${i}`,
unit: `单位${i}`,
}));
tableData.value = data;
total.value = 100; // 假设总条数为 100
};
// 切换对话框的可见状态
const openDialog = () => {
dialogShow.value = true;
};
// 关闭对话框
const handleClose = () => {
dialogShow.value = false;
};
// 处理分页器当前页改变
const handleCurrentChange = async val => {
console.log('current', val);
currentPage.value = val;
await fetchData();
};
// 处理选项变化
const handleSelectionChange = val => {
selectedRows.value = val;
};
// 处理每页显示的条数改变
const handleSizeChange = async val => {
pageSize.value = val;
await fetchData();
};
// 处理选择按钮点击
const handleSelect = () => {
if (props.check === 'radio') {
const selectedData = tableData.value.find(row => row.id === selectedRow.value);
$emit('select', selectedData);
} else {
$emit('select', selectedRows.value);
}
handleClose();
};
// 暴露方法和属性
defineExpose({ openDialog });
// 初始获取数据
fetchData();
</script>
这里多啰嗦一句单选
,我这里是自定义列,使用单选框的方式实现的
html
<el-table-column v-else-if="check === 'radio'" width="50">
<template #default="scope">
<el-radio v-model="selectedRow" :label="scope.row.id"></el-radio>
</template>
</el-table-column>
<script>
// 选中的行的数据
const selectedRow = ref(null);
// 处理选择按钮点击
const handleSelect = () => {
if (props.check === 'radio') {
const selectedData = tableData.value.find(row => row.id === selectedRow.value);
$emit('select', selectedData);
}
};
</script>
为什么要这样呢,因为我开始是使用多选加反选的方式实现单选,但这样存在一个bug,就是多选框的表头有个全选按钮,点击那个全选的时候会出现反选的问题。
html
<template>
<el-table
ref="tableRef"
:data="tableData"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection"></el-table-column>
......
</el-table>
</template>
<script>
const selectedRow = ref(null);
const handleSelectionChange = (val: []) => {
console.log(val);
if (val.length > 1) {
// 单选
tableRef.value!.toggleRowSelection(val[0], val[val.length - 1]);
selectedRow .value = [val[val.length - 1]];
} else {
// 多选
selectedRow .value = val;
}
}
</script>