Bootstrap

vue3+ts+element封装一个简易的curd

vue3+ts+element封装一个简易的curd

闲来无趣做一个简单的table封装,不喜勿喷
在这里插入图片描述

首先创建一个公共的Table.vue/pagination.vue文件

Table.vue

<template>
  <div class="red-row-class">
    <el-table class="table" :data="tableData" v-loading="loading" :row-class-name="rowClassName" @selection-change="handleSelectionChange" border>
      <!-- 多选 -->
      <el-table-column v-if="selectionIsNeed" type="selection" width="55"> </el-table-column>
      <!-- 序号 -->
      <el-table-column label="序号" align="center" width="80" v-if="indexFlag" type="index"></el-table-column>
      <!-- 表头 -->
      <el-table-column v-for="column in columns" :key="column.prop" :prop="column.prop" :label="column.label" :min-width="column.minWidth"> </el-table-column>
      <!-- 操作 -->
      <el-table-column v-if="optionIsNeed" fixed="right" label="操作" :width="optionWidth">
        <template #default="{ row, $index }">
          <slot name="prev" :scope="row"></slot>
          <el-button v-if="editIsNeed" @click="handleEdit($index, row)" type="text" size="small">编辑</el-button>
          <el-button v-if="deleteIsNeed" @click="handleDelete($index, row)" type="text" size="small">删除</el-button>
          <slot name="next" :scope="row"></slot>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>
<script setup lang="ts">
type Props = {
  columns: Array<{
    prop: string;
    label: string;
    minWidth: string;
  }>;
  tableData: Array<any>;
  loading: boolean;
  selectionIsNeed: boolean;
  optionIsNeed: boolean;
  editIsNeed: boolean;
  deleteIsNeed: boolean;
  indexFlag: boolean;
  optionWidth: string;
  rowClassName: string;
};
//类型字面量模式
withDefaults(defineProps<Props>(), {
  loading: false,
  selectionIsNeed: false,
  optionIsNeed: false,
  editIsNeed: false,
  deleteIsNeed: false,
  indexFlag: false,
  optionWidth: '100px',
  rowClassName: '',
});

const emit = defineEmits(['handleEdit', 'handleDelete']);

//修改
function handleEdit(index: number, row: any[]) {
  emit('handleEdit', index, row);
}

//删除
function handleDelete(index: number, row: any[]) {
  emit('handleDelete', index, row);
}
</script>
<script lang="ts">
//区分组件
export default {
  name: 'Table',
};
</script>
<style lang="less" scoped>
.table {
  width: 100%;
  font-size: 14px;
  margin-top: 15px;
}
</style>


再来建一个 pagination.vue 组件来写 分页器

pagination.vue

<template>
  <div class="pagination">
    <el-pagination background layout="total, prev, pager, next" :total="totalNum" :current-page="currentPage" :page-size="pageSize" @current-change="currentChange">
    </el-pagination>
  </div>
</template>
<script setup lang="ts">
type Props = {
  totalNum: number;
  currentPage: number;
  pageSize: number;
};
withDefaults(defineProps<Props>(), {
  pageSize: 10,
  currentPage: 1,
  totalNum: 0,
});

const emit = defineEmits(['currentChange']);

//点击分页
function currentChange(val: number) {
  emit('currentChange', val);
}
</script>
<script lang="ts">
//区分组件
export default {
  name: 'Pagination',
};
</script>
<style lang="less" scoped>
.pagination {
  margin-top: 20px;
  display: flex;
  justify-content: flex-end;
}
</style>

然后去正式的view文件夹下建一个list.vue文件来引入上面的公共组件

list.vue

<template>
  <!-- 列表 -->
  <Table
    :columns="columns"
    :tableData="tableList.list"
    :optionWidth="200"
    :optionIsNeed="true"
    :editIsNeed="true"
    :deleteIsNeed="true"
    @handleEdit="handleEdit"
    @handleDelete="handleDelete"
  >
    <template #end_day="slotProps"> 还剩 {{ slotProps.row.end_day }} 天过期 </template>
    <template #status="slotProps">
      {{ slotProps.row.status ? '正常' : '过期' }}
    </template>
    <template #prev="{ scope }">
      <el-button type="text" size="small" @click="handleFly(scope)">查看</el-button>
    </template>
  </Table>
  <!-- 分页 -->
  <Pagination :currentPage="currentPage" :totalNum="totalNum" @currentChange="currentChange" />
  <!-- 添加/修改 -->
  <Poput :item="item.editRow" :Tips="item.Tips" :dialogVisible="item.dialogVisible" @on-close="close" @on-submit="submit" />
</template>
<script setup lang="ts">
import { ElMessage, ElMessageBox } from 'element-plus';
import Table from '../../components/Table/table.vue';
import Pagination from '../../components/Table/Pagination.vue';
import Poput from './Popup.vue';
//分页参数
const currentPage = ref(1);
const totalNum = ref(0);
//列表接口
interface TableItem {
  date: string;
  name: string;
  state: string;
  sex: string;
  city: string;
  address: string;
}
type Item = {
  list: TableItem[];
};
//表头
const columns = reactive([
  { prop: 'name', label: '名称', minWidth: 120 },
  { prop: 'sex', label: '性别', minWidth: 120 },
  { prop: 'date', label: '日期', minWidth: 120 },
  { prop: 'state', label: '省份', minWidth: 120 },
  { prop: 'city', label: '城市', minWidth: 120 },
  { prop: 'address', label: '地址', minWidth: 120 },
]);

const tableList = reactive<Item>({
  list: [],
});
//数据
tableList.list = [
  {
    date: '2021-10-10',
    name: '张三',
    sex: '男',
    state: '江苏',
    city: '南京',
    address: '钟楼区',
  },
];
//查看
function handleFly(row: TableItem) {
  console.log(row);
}
const item = reactive({
  editRow: {},
  Tips: '',
  dialogVisible: false,
  index: -1,
});
//修改
function handleEdit(index: number, row: TableItem) {
  item.editRow = JSON.parse(JSON.stringify(row));
  item.Tips = '修改';
  item.dialogVisible = true;
  item.index = index;
}
function submit(row: TableItem) {
  item.dialogVisible = false;
  console.log(row);
}
//删除
function handleDelete(index: number, row: TableItem) {
  console.log(index, row);
  ElMessageBox.confirm('确定要删除该条信息吗?', 'Warning', {
    confirmButtonText: 'OK',
    cancelButtonText: 'Cancel',
    type: 'warning',
  })
    .then(() => {
      ElMessage({
        type: 'success',
        message: 'Delete success',
      });
    })
    .catch(() => {
      ElMessage({
        type: 'info',
        message: 'Delete canceled',
      });
    });
}
//分页
function currentChange(val: number) {
  currentPage.value = val;
}
//关闭弹窗
function close(e: boolean) {
  item.dialogVisible = e;
}
</script>
<style lang="less" scoped></style>

跟这个组件同级的弹窗组件 Popup.vue 也建立一下

Popup.vue

<template>
  <div>
    <el-dialog v-model="dialogVisible" :title="Tips" width="30%" :close-on-click-modal="false">
      <el-form ref="addForm" :model="item" label-width="100px" :rules="rules">
        <el-form-item label="时间" prop="date">
          <el-date-picker v-model="item.date" type="date" placeholder="请输入时间" format-value="yy-mm-dd" />
        </el-form-item>
        <el-form-item label="姓名" prop="name">
          <el-input v-model="item.name" placeholder="请输入姓名"></el-input>
        </el-form-item>
        <el-form-item label="性别" prop="sex">
          <el-input v-model="item.sex" placeholder="请输入姓名"></el-input>
        </el-form-item>
        <el-form-item label="省份" prop="state">
          <el-input v-model="item.state" placeholder="请输入省份"></el-input>
        </el-form-item>
        <el-form-item label="城市" prop="city">
          <el-input v-model="item.city" placeholder="请输入城市"></el-input>
        </el-form-item>
        <el-form-item label="详细地址" prop="address">
          <el-input v-model="item.address" placeholder="请输入详细地址"></el-input>
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="close(addForm)">关闭</el-button>
          <el-button type="primary" @click="submit(addForm)">确定</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>
<script setup lang="ts">
import { FormInstance, FormItemRule } from 'element-plus';
const addForm = ref<FormInstance>();
interface TableItem {
  date: string;
  name: string;
  state: string;
  sex: string;
  city: string;
  address: string;
}

type Prop = {
  item: TableItem;
  dialogVisible: boolean;
  Tips: string;
};

const emit = defineEmits(['on-close', 'on-submit']);

const data = withDefaults(defineProps<Prop>(), {
  dialogVisible: false,
  Tips: '弹窗',
});

function close(formEl: FormInstance | undefined) {
  if (!formEl) return;
  formEl.resetFields();
  emit('on-close', false);
}

async function submit(formEl: FormInstance | undefined) {
  if (!formEl) return;
  await formEl.validate(valid => {
    if (valid) {
      emit('on-submit', data.item);
      close(formEl);
    }
  });
}
</script>
<script lang="ts">
//区分组件
export default {
  name: 'Poput',
};
</script>
<style lang="less" scoped></style>

基本的curd功能就完成了

;