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

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

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

总结

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

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

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

继续做吧!!!

相关推荐
万能程序员-传康Kk11 分钟前
食物数据分析系统vue+flask
前端·vue.js·flask
老华带你飞1 小时前
音乐网站|基于SprinBoot+vue的音乐网站(源码+数据库+文档)
java·前端·数据库·vue.js·论文·毕设·音乐网站
是程序喵呀1 小时前
uni-app使用web-view组件APP实现返回上一页
前端·uni-app
Joker Zxc2 小时前
【前端基础】9、CSS的动态伪类(hover、visited、hover、active、focus)【注:本文只有几个粗略说明】
前端·css
2401_837088502 小时前
CSS flex:1
前端·css
发呆小天才yy6 小时前
uniapp 微信小程序使用图表
前端·微信小程序·uni-app·echarts
@PHARAOH8 小时前
HOW - 在 Mac 上的 Chrome 浏览器中调试 Windows 场景下的前端页面
前端·chrome·macos
源码云商9 小时前
Spring Boot + Vue 实现在线视频教育平台
vue.js·spring boot·后端
月月大王10 小时前
easyexcel导出动态写入标题和数据
java·服务器·前端
JC_You_Know11 小时前
多语言网站的 UX 陷阱与国际化实践陷阱清单
前端·ux