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>
相关推荐
正小安18 分钟前
如何在微信小程序中实现分包加载和预下载
前端·微信小程序·小程序
_.Switch2 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光2 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   2 小时前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发
长路 ㅤ   2 小时前
vue-live2d看板娘集成方案设计使用教程
前端·javascript·vue.js·live2d
Fan_web2 小时前
jQuery——事件委托
开发语言·前端·javascript·css·jquery
安冬的码畜日常2 小时前
【CSS in Depth 2 精译_044】第七章 响应式设计概述
前端·css·css3·html5·响应式设计·响应式
莹雨潇潇3 小时前
Docker 快速入门(Ubuntu版)
java·前端·docker·容器
Jiaberrr3 小时前
Element UI教程:如何将Radio单选框的圆框改为方框
前端·javascript·vue.js·ui·elementui
Tiffany_Ho4 小时前
【TypeScript】知识点梳理(三)
前端·typescript