vue3和el-table实现表格内新增、保存、取消、修改、删除——不用弹窗(一)

1.各个操作逻辑流程

如图1所示:初始时,表格为空表格或者含有数据的表格。

2.各个操作的方法逻辑

如图2所示:初始时数据的含义如下:

1. beforeEditRow表示点击修改后,将修改前的数据暂存,用于后续取消时恢复原数据;
2. addRow表示点击新增后,新的一行空数据;
3. editingIndex表示当前正在编辑的行,-1表示没有数据行被编辑;
4. data表示表格数据,可以为空,或者含有一定行;

3.vue3代码实现结果

代码实现页面如下,拥有数据校验功能。

4. 源代码

整体代码采用vue3的script setup风格➕element-plus➕tailwindcss,采用element-plus的playground,便于分享和查看。代码实现页面链接。欢迎讨论分享,指出不足之处,共同进步!

<template>
    <el-form :model="formData" ref="formRef" label-width="auto" :rules="rules">
        <el-form-item label="姓名" prop="name">
            <el-input v-model="formData.name" placeholder="请输入姓名" style="width: 800px" />
        </el-form-item>
        <el-form-item label="性别" prop="sex">
            <el-select
                v-model="formData.sex"
                placeholder="请选择性别"
                filterable
                size="large"
                style="width: 800px"
                clearable
            >
                <el-option
                    v-for="item in sexOptions"
                    :key="item.value"
                    :label="item.label"
                    :value="item.value"
                >
                    {{ item.label }}
                </el-option>
            </el-select>
        </el-form-item>
        <el-form-item label="年龄" prop="age">
            <el-input-number
                v-model="formData.age"
                placeholder="请输入年龄"
                style="width: 800px"
            ></el-input-number>
        </el-form-item>
        <el-form-item label="地址" prop="address">
            <el-input
                v-model="formData.address"
                placeholder="请输入地址"
                style="width: 800px"
            ></el-input>
        </el-form-item>
    </el-form>
    <div class="mb-3">
        <div class="font-bold text-16px">新增家庭信息</div>
    </div>
    <!-- 添加家庭信息 -->
    <el-form ref="familyInfoRef">
        <el-table :data="familyInfo" border>
            <template #empty>
                <div class="flex flex-row justify-center items-center space-x-2">
                    <span>点击 + 按钮新增家庭成员</span>
                </div>
            </template>
            <el-table-column prop="relation" label="关系" align="center">
                <template #default="{ row, $index }">
                    <el-input
                        v-if="$index === editingIndex"
                        v-model="row.relation"
                        placeholder="请输入关系"
                        size="small"
                    >
                    </el-input>
                    <span v-else>{{ row.relation }}</span>
                </template>
            </el-table-column>
            <el-table-column prop="name" label="姓名" min-width="60px" align="center">
                <template #default="{ row, $index }">
                    <el-input
                        v-if="$index === editingIndex"
                        v-model="row.name"
                        placeholder="请输入姓名"
                        size="small"
                    >
                    </el-input>
                    <span v-else>{{ row.name }}</span>
                </template>
            </el-table-column>
            <el-table-column prop="sex" label="性别" min-width="100px" align="center">
                <template #default="{ row, $index }">
                    <el-select
                        v-if="$index === editingIndex"
                        v-model="row.sex"
                        filterable
                        clearable
                        placeholder="请选择性别"
                        size="small"
                        style="width: 100%"
                    >
                        <el-option
                            v-for="item in sexOptions"
                            :key="item.value"
                            :label="item.label"
                            :value="item.value"
                        />
                    </el-select>
                    <span v-else>{{ getSexLabel(row.sex) }}</span>
                </template>
            </el-table-column>
            <el-table-column prop="age" label="年龄" min-width="80px" align="center">
                <template #default="{ row, $index }">
                    <el-input
                        v-if="$index === editingIndex"
                        v-model="row.age"
                        placeholder="请输入年龄"
                        size="small"
                    >
                    </el-input>
                    <span v-else>{{ row.age }}</span>
                </template>
            </el-table-column>
            <el-table-column prop="address" label="地址" min-width="100px" align="center">
                <template #default="{ row, $index }">
                    <el-input
                        v-if="$index === editingIndex"
                        v-model="row.address"
                        placeholder="请输入地址"
                        size="small"
                    >
                    </el-input>
                    <span v-else>{{ row.address }}</span>
                </template>
            </el-table-column>
            <el-table-column label="操作" align="center">
                <template #default="{ row, $index }">
                    <div class="flex flex-row justify-center items-center">
                        <template v-if="$index === editingIndex">
                            <el-button
                                type="success"
                                size="small"
                                plain
                                @click="handleSave(row, $index)"
                                >保存</el-button
                            >
                            <el-button
                                type="info"
                                size="small"
                                plain
                                @click="handleCancel(row, $index)"
                                >取消</el-button
                            >
                        </template>
                        <template v-else>
                            <el-button
                                type="primary"
                                size="small"
                                plain
                                @click="handleEdit(row, $index)"
                            >
                                修改
                            </el-button>
                            <el-popconfirm
                                title="是否确认删除?"
                                @confirm="handleDelete(row, $index)"
                                style="margin-left: 10px"
                            >
                                <template #reference>
                                    <el-button type="danger" size="small" plain>删除</el-button>
                                </template>
                            </el-popconfirm>
                        </template>
                    </div>
                </template>
            </el-table-column>
        </el-table>
    </el-form>

    <!-- 添加新行 -->
    <div class="flex justify-center mt-[4px]">
        <el-icon @click="handleAdd()" class="icon" size="24" color="#fb7a14"
            ><CirclePlusFilled />
        </el-icon>
    </div>
</template>

<script setup lang="ts">
import { ref, reactive } from 'vue'
import { ElMessage, ElMessageBox, type FormInstance } from 'element-plus'
import { CirclePlusFilled } from '@element-plus/icons-vue'

/* --------------------------------- 用户数据类型 --------------------------------- */
interface User {
    name: string
    age: number
    sex: string
    address: string
    email: string
}

interface FamilyInfo {
    relation: string
    name: string
    age: number
    sex: string
    address: string
}

const sexOptions = [
    { value: 1, label: '男' },
    { value: 2, label: '女' }
]

/* ---------------------------------- 表格数据 ---------------------------------- */
const formData = reactive<User>({
    name: '',
    age: 0,
    sex: '',
    address: '',
    email: ''
})

const formRef = ref<FormInstance>()

const familyInfo = ref<FamilyInfo[]>([])

const familyInfoRef = ref<FormInstance>()

const rules = {
    name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
    age: [{ required: true, message: '请选择出生日期', trigger: 'change' }],
    sex: [{ required: true, message: '请选择性别', trigger: 'change' }]
}

/* ------------------------------ 当前编辑行下标 ------------------------------ */
const editingIndex = ref<number>(-1)

/* ------------------------------- 编辑行修改前的数据 ------------------------------- */
const beforeEditRow = ref<FamilyInfo>({
    relation: '',
    name: '',
    age: 0,
    sex: '',
    address: ''
})

/* --------------------------------- 新增行的空数据 -------------------------------- */
const addContractRow: FamilyInfo = {
    relation: '',
    name: '',
    age: 0,
    sex: '',
    address: ''
}

/* ---------------------------------- 重置编辑行 --------------------------------- */
const resetTable = () => {
    editingIndex.value = -1
    beforeEditRow.value = { ...addContractRow }
}

/* ---------------------------------- 表格操作 ---------------------------------- */
const handleAdd = () => {
    if (editingIndex.value > -1) {
        ElMessage.warning('请先完成修改中的行')
        return
    }
    editingIndex.value = familyInfo.value.length
    familyInfo.value.push({ ...addContractRow })
}

const handleEdit = (row: FamilyInfo, index: number) => {
    if (editingIndex.value > -1) {
        ElMessage.warning('请先完成修改中的行')
        return
    }
    beforeEditRow.value = { ...row }
    editingIndex.value = index
}

const handleSave = (row: FamilyInfo, index: number) => {
    if (!row.relation || !row.name || !row.age || !row.sex) {
        ElMessage.warning('请填写所有必填字段再保存')
        return
    }
    familyInfo.value[index] = { ...row }
    resetTable()
}

const handleDelete = (row: FamilyInfo, index: number) => {
    familyInfo.value.splice(index, 1)
}

const handleCancel = (row: FamilyInfo, index: number) => {
    if (Object.values(beforeEditRow.value).some((value) => value !== '')) {
        familyInfo.value[index] = { ...beforeEditRow.value }
    } else {
        familyInfo.value.splice(index, 1)
    }
    resetTable()
}

const getSexLabel = (value: number) => {
    return sexOptions.find((option) => option.value === value)?.label || ''
}
</script>

posted @   suyiranzhi  阅读(901)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示