vue3中基于element-plus封装一个表格弹框组件,要求可以单选和多选table数据

单选:

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>
相关推荐
无双_Joney11 分钟前
[更新迭代 - 1] Nestjs 在24年底更新了啥?(功能篇)
前端·后端·nestjs
在云端易逍遥13 分钟前
前端必学的 CSS Grid 布局体系
前端·css
EMT13 分钟前
在 Vue 项目中使用 URL Query 保存和恢复搜索条件
javascript·vue.js
ccnocare14 分钟前
选择文件夹路径
前端
艾小码15 分钟前
还在被超长列表卡到崩溃?3招搞定虚拟滚动,性能直接起飞!
前端·javascript·react.js
闰五月15 分钟前
JavaScript作用域与作用域链详解
前端·面试
泉城老铁19 分钟前
idea 优化卡顿
前端·后端·敏捷开发
前端康师傅19 分钟前
JavaScript 作用域常见问题及解决方案
前端·javascript
司宸21 分钟前
Prompt结构化输出:从入门到精通的系统指南
前端