自研国产零依赖前端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"/>

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

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

总结

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

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

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

继续做吧!!!

相关推荐
gnip6 小时前
企业级配置式表单组件封装
前端·javascript·vue.js
一只叫煤球的猫7 小时前
写代码很6,面试秒变菜鸟?不卖课,面试官视角走心探讨
前端·后端·面试
excel8 小时前
Three.js 材质(Material)详解 —— 区别、原理、场景与示例
前端
掘金安东尼8 小时前
抛弃自定义模态框:原生Dialog的实力
前端·javascript·github
hj5914_前端新手12 小时前
javascript基础- 函数中 this 指向、call、apply、bind
前端·javascript
薛定谔的算法12 小时前
低代码编辑器项目设计与实现:以JSON为核心的数据驱动架构
前端·react.js·前端框架
Hilaku12 小时前
都2025年了,我们还有必要为了兼容性,去写那么多polyfill吗?
前端·javascript·css
yangcode12 小时前
iOS 苹果内购 Storekit 2
前端
LuckySusu12 小时前
【js篇】JavaScript 原型修改 vs 重写:深入理解 constructor的指向问题
前端·javascript
LuckySusu12 小时前
【js篇】如何准确获取对象自身的属性?hasOwnProperty深度解析
前端·javascript