自研国产零依赖前端UI框架实战007 封装编辑和删除相关的功能组件

前言

前面我们已经实现了一个表格, 能够展示用户的信息, 一个分页能够执行分页获取用户信息.

到目前为止, 数据的渲染, 我们基本就做的差不多了, 接下来我们来扩展一下表格, 让其支持添加按钮, 我们在里面添加编辑按钮和删除按钮.

表格样式调整

我调整了一下表格的样式, 增加了操作列, 目前看起来是这样的:

代码里面增加了操作这一列:

操作这一列可以根据一个叫做operator的属性进行控制, 默认是true, 如果改成false, 则不显示操作列.

稍微调整一下删除按钮的样式

暴露按钮点击方法

首先是在组件中添加要暴露的方法:

js 复制代码
const emit = defineEmits(['edit', 'delete']);
const onEdit = (index, item) => emit('edit', index, item) // 编辑
const onDelete = (index, item) => emit('delete', index, item) // 删除

接着给按钮绑定:

html 复制代码
<button @click.stop="onEdit(k, v)">编辑</button>
<button class="delete" @click.stop="onDelete(k,v)">删除</button>

在App.vue中监听编辑和删除这两个事件:

vue 复制代码
<zdp_table1
        :columns="columns"
        :data="data"
        @edit="onEdit"
        @delete="onDelete"
    />

再简单的实现事件的监听:

js 复制代码
const onEdit = (index, item) => {
  console.log("编辑", index, item)
}
const onDelete = (index, item) => {
  console.log("删除", index, item)
}

此时, 当我们点击编辑按钮的删除按钮的时候, 控制台会输出对应的内容.

此时页面效果如下:

App.vue的完整代码如下:

html 复制代码
<script setup>
import zdp_table1 from "./zdpui/components/zdp_table1.vue";
import zdp_page1 from "./zdpui/components/zdp_page1.vue";
import random from "./zdpui/js/random.js";
import {ref} from "vue";

const columns = [
  {
    title: "员工编号",
    key: "id",
    width: 80,
    align: "center"
  },
  {
    title: "姓名",
    key: "name",
    width: 100,
    align: "center"
  },
  {
    title: "年龄",
    key: "age",
    width: 100,
    align: "center"
  }
]

const page = ref(1);
const size = ref(10);
const total = ref(100);
const data = ref(random.users(size.value))

const onChangePage = (v) => {
  page.value = v
  const newData = random.getPageUser(
      page.value,
      size.value,
  )
  data.value = newData.data
  total.value = total.value
}
const onEdit = (index, item) => {
  console.log("编辑", index, item)
}
const onDelete = (index, item) => {
  console.log("删除", index, item)
}
</script>
<template>
  <div>
    <zdp_table1
        :columns="columns"
        :data="data"
        @edit="onEdit"
        @delete="onDelete"
    />
    <zdp_page1
        :page="page"
        :size="size"
        :total="total"
        @change="onChangePage"
    />
  </div>
</template>

删除确认

当我们点击删除的时候, 希望能够弹出一个确认删除的对话框, 比如像下面这样.

这个我已经封装好了, 比想象中要简单的多, 完整代码如下:

html 复制代码
<script setup>
import {defineEmits, defineProps} from 'vue';

const props = defineProps({
  show: {
    type: Boolean,
    default: false
  },
  title: {
    type: String,
    default: '确认删除'
  },
  content: {
    type: String,
    default: '你确定要删除该项目吗?此操作不可逆。'
  },
  ok: {
    type: String,
    default: '确认'
  },
  cancel: {
    type: String,
    default: '取消'
  }
});

const emit = defineEmits(['confirm', 'close']);
const onClose = () => emit('close')
const onConfirm = () => emit('confirm')
</script>

<template>
  <div class="confirm-delete-dialog" v-if="props.show">
    <div class="dialog-overlay" @click.self="onClose"></div>
    <div class="dialog-content">
      <h2>{{ props.title }}</h2>
      <p>{{ props.content }}</p>
      <div class="dialog-buttons">
        <button @click="onConfirm">{{ props.ok }}</button>
        <button @click="onClose">{{ props.cancel }}</button>
      </div>
    </div>
  </div>
</template>


<style scoped>
.confirm-delete-dialog {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
}

.dialog-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
}

.dialog-content {
  background-color: #fff;
  padding: 20px;
  border-radius: 10px;
  box-shadow: 0 0 20px rgba(0, 0, 0, 0.3);
  z-index: 1001;
  text-align: center;
}

.dialog-content h2 {
  margin-top: 0;
  color: #009FFF;
}

.dialog-content p {
  margin-bottom: 20px;
}

.dialog-buttons button {
  padding: 10px 20px;
  margin: 0 10px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  font-weight: bold;
  color: white;
  transition: all 0.3s ease-in-out;
}

.dialog-buttons button:first-child {
  background: linear-gradient(45deg, #C70039, #FF5733);
  box-shadow: 0 5px 10px rgba(199, 0, 57, 0.4);
}

.dialog-buttons button:first-child:hover {
  transform: translateY(-3px);
  box-shadow: 0 8px 15px rgba(199, 0, 57, 0.6);
  background: linear-gradient(45deg, #FF5733, #FF8C00);
}

.dialog-buttons button:first-child:active {
  transform: translateY(1px);
  box-shadow: 0 3px 8px rgba(199, 0, 57, 0.8);
  background: linear-gradient(45deg, #900C3F, #C70039);
}

.dialog-buttons button:last-child {
  background: linear-gradient(45deg, #009FFF, #0066CC);
  box-shadow: 0 5px 10px rgba(0, 159, 255, 0.4);
}

.dialog-buttons button:last-child:hover {
  transform: translateY(-3px);
  box-shadow: 0 8px 15px rgba(0, 159, 255, 0.6);
  background: linear-gradient(45deg, #00BFFF, #0088EE);
}

.dialog-buttons button:last-child:active {
  transform: translateY(1px);
  box-shadow: 0 3px 10px rgba(0, 159, 255, 0.8);
  background: linear-gradient(45deg, #0077DD, #0055AA);
}
</style>

在App.vue中的使用代码如下:

编辑弹窗

效果预览:

此时App.vue代码如下:

vue 复制代码
<script setup>
import zdp_table1 from "./zdpui/components/zdp_table1.vue";
import zdp_page1 from "./zdpui/components/zdp_page1.vue";
import random from "./zdpui/js/random.js";
import {ref} from "vue";
import zdp_confirm1 from "./zdpui/components/zdp_confirm1.vue";
import zdp_modal1 from "./zdpui/components/zdp_modal1.vue";
import Zdp_input1 from "./zdpui/components/zdp_input1.vue";

const columns = [
  {
    title: "员工编号",
    key: "id",
    width: 80,
    align: "center"
  },
  {
    title: "姓名",
    key: "name",
    width: 100,
    align: "center"
  },
  {
    title: "年龄",
    key: "age",
    width: 100,
    align: "center"
  }
]

const page = ref(1);
const size = ref(10);
const total = ref(100);
const data = ref(random.users(size.value))

const onChangePage = (v) => {
  page.value = v
  const newData = random.getPageUser(
      page.value,
      size.value,
  )
  data.value = newData.data
  total.value = total.value
}
const onEdit = (index, item) => {
  console.log("编辑", index, item)
  showEditDialog.value = true;
}
const onDelete = (index, item) => {
  console.log("删除", index, item)
  showDeleteDialog.value = true;
}
const showDeleteDialog = ref(false);
const onConfirmDelete = () => {
  console.log("确认删除");
  showDeleteDialog.value = false;
};
const onCloseDeleteDialog = () => {
  console.log("取消删除");
  showDeleteDialog.value = false;
};

const showEditDialog = ref(false);
const formData = ref({name: "张三", age: 23});

const handleEditConfirm = (userData) => {
  console.log('确认编辑操作,用户数据:', userData);
  // 在这里添加编辑逻辑,如发送编辑请求等
};

const handleCloseDialog = () => {
  showEditDialog.value = false;
};
</script>
<template>
  <div>
    <zdp_table1
        :columns="columns"
        :data="data"
        @edit="onEdit"
        @delete="onDelete"
    />
    <zdp_page1
        :page="page"
        :size="size"
        :total="total"
        @change="onChangePage"
    />
    <zdp_confirm1
        :show="showDeleteDialog"
        @confirm="onConfirmDelete"
        @close="onCloseDeleteDialog"
    />
    <zdp_modal1
        :show="showEditDialog"
        @confirm="handleEditConfirm"
        @close="handleCloseDialog"
    >
      <zdp_input1
          label="姓名"
          v-model="formData.name"
          placeholder="请输入姓名"
      />
      <zdp_input1
          label="年龄"
          v-model="formData.age"
          placeholder="请输入年龄"
      />
    </zdp_modal1>
  </div>
</template>

继续封装按钮

到这一步的时候, 发现按钮有很多地方都是一样的, 重复的, 所以决定对按钮进行封装.

按钮组件的内容如下:

html 复制代码
<script setup>
import {defineProps, defineEmits} from 'vue';

const props = defineProps({
  text: {
    type: String,
    default: '按钮',
  },
  type: {
    type: String,
    // primary,danger
    default: 'primary',
  }
})
const emits = defineEmits(['click'])
</script>

<template>
  <button
      @click="emits('click')"
      :class="props.type"
  >
    {{ props.text }}
  </button>
</template>

<style scoped>
button {
  padding: 10px 20px;
  margin: 0 10px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  font-weight: bold;
  color: white;
  transition: all 0.3s ease-in-out;
}

button.danger {
  background: linear-gradient(45deg, #C70039, #FF5733);
  box-shadow: 0 5px 10px rgba(199, 0, 57, 0.4);
}

button.danger:hover {
  transform: translateY(-3px);
  box-shadow: 0 8px 15px rgba(199, 0, 57, 0.6);
  background: linear-gradient(45deg, #FF5733, #FF8C00);
}

button.danger:active {
  transform: translateY(1px);
  box-shadow: 0 3px 8px rgba(199, 0, 57, 0.8);
  background: linear-gradient(45deg, #900C3F, #C70039);
}

button.primary {
  background: linear-gradient(45deg, #009FFF, #0066CC);
  box-shadow: 0 5px 10px rgba(0, 159, 255, 0.4);
}

button.primary:hover {
  transform: translateY(-3px);
  box-shadow: 0 8px 15px rgba(0, 159, 255, 0.6);
  background: linear-gradient(45deg, #00BFFF, #0088EE);
}

button.primary:active {
  transform: translateY(1px);
  box-shadow: 0 3px 10px rgba(0, 159, 255, 0.8);
  background: linear-gradient(45deg, #0077DD, #0055AA);
}
</style>

使用方法如下:

html 复制代码
<zdp_button1/>
<zdp_button1 type="danger"/>

在界面中的显示效果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

总结

现在, 我们已经有了自己的按钮组件, 确认框组件, 编辑表单组件, 组件越来越多了.

不过这个时候, 组件之间的拆分, 组合也变得越来越复杂了, 比如这个编辑表单组件, 就因为有输入框组件, 按钮组件, 确认框组件等多个组件的组合, 显得很复杂, 样式调整稍微麻烦了一点点.

不过一切都还比较顺利!!!

继续做吧!!!

相关推荐
一蓑烟雨,一任平生22 分钟前
鸿蒙H5调试方法
前端·华为·h5·harmonyos
黄思搏23 分钟前
基于标注平台数据的 Unity UI 自动化构建工作流设计与工程实践
ui·unity·蓝湖·vectoui
Canace35 分钟前
使用大模型来维护知识库
前端·人工智能
HashTang36 分钟前
用自然语言驱动的开源 3D 建筑设计编辑器-Aedifex
前端·github·ai编程
0vvv01 小时前
2026-NCTF-web-N-RustPICA
前端·ctf
前进的李工1 小时前
MySQL角色管理:权限控制全攻略
前端·javascript·数据库·mysql
芯智工坊1 小时前
第13章 Mosquitto监控与日志管理
前端·网络·人工智能·mqtt·开源
洒满阳光的庄园2 小时前
Electron 桌面端打包流程说明
前端·javascript·electron
Jagger_2 小时前
模型能力边界外扩时,工作到底在怎样被重做?
前端
SuperEugene2 小时前
前端通用基础组件设计:按钮/输入框/弹窗,统一设计标准|组件化设计基础篇
前端·javascript·vue.js·架构