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

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

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

总结

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

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

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

继续做吧!!!

相关推荐
1024小神15 分钟前
更改github action工作流的权限
前端·javascript
Epicurus20 分钟前
JavaScript无阻塞加载的方式
前端·javascript
1024小神22 分钟前
tauri程序使用github action发布linux中arm架构
前端·javascript
ahhdfjfdf24 分钟前
最全的`Map` 和 `WeakMap`的区别
前端
JYeontu29 分钟前
实现一个带@功能的输入框组件
前端·javascript·vue.js
一颗奇趣蛋1 小时前
vue-router的query和params的区别(附实际用法)
前端·vue.js
孤城2861 小时前
MAC电脑常用操作
前端·macos·快捷键·新手·电脑使用
木亦Sam1 小时前
Vue DevTools逆向工程:自己实现一个组件热更新调试器
前端
酷酷的阿云1 小时前
动画与过渡效果:UnoCSS内置动画库的实战应用
前端·css·typescript
dleei1 小时前
使用docker创建gitlab仓库
前端·docker·gitlab