后台数据管理系统 - 项目架构设计-Vue3+axios+Element-plus(0926)
十四、文章分类添加编辑 [element-plus 弹层]
Git仓库:https://gitee.com/msyycn/vue3-hei-ma.git
点击显示弹层
- 准备弹层
const dialogVisible = ref(false)
<el-dialog v-model="dialogVisible" title="添加弹层" width="30%">
<div>我是内容部分</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary"> 确认 </el-button>
</span>
</template>
</el-dialog>
- 点击事件
<template #extra><el-button type="primary" @click="onAddChannel">添加分类</el-button></template>
const onAddChannel = () => {
dialogVisible.value = true
}
封装弹层组件 ChannelEdit
添加 和 编辑,可以共用一个弹层,所以可以将弹层封装成一个组件
组件对外暴露一个方法 open, 基于 open 的参数,初始化表单数据,并判断区分是添加 还是 编辑
- open({ }) => 添加操作,添加表单初始化无数据
- open({ id: xx, … }) => 编辑操作,编辑表单初始化需回显
具体实现:
- 封装组件
article/components/ChannelEdit.vue
<script setup>
import { ref } from 'vue'
const dialogVisible = ref(false)
const open = async (row) => {
dialogVisible.value = true
console.log(row)
}
defineExpose({
open
})
</script>
<template>
<el-dialog v-model="dialogVisible" title="添加弹层" width="30%">
<div>我是内容部分</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary"> 确认 </el-button>
</span>
</template>
</el-dialog>
</template>
- 通过 ref 绑定
const dialog = ref()
<!-- 弹窗 -->
<channel-edit ref="dialog"></channel-edit>
- 点击调用方法显示弹窗
const onAddChannel = () => {
dialog.value.open({})
}
const onEditChannel = (row) => {
dialog.value.open(row)
}
ChannelEdit.vue
(封装的组件)
<script setup>
import {ref} from 'vue'
const dialogVisible = ref(false) //弹层状态
// 组件对外暴露一个方法,open ,基于open 传来的参数,区分添加还是编辑
// open ({}) => 表单无需渲染,说明是添加分
// open ({id, name}) => 表单需要渲染,说明是编辑分类
// open调用后,可以打开弹窗
const open = (row) =>{
console.log(row)
dialogVisible.value = true
}
// 向外暴露一个方法,close,关闭弹窗
defineExpose({
open
})
</script>
<template>
//弹层
<el-dialog
v-model="dialogVisible"
title="添加弹层"
width="500"
:before-close="handleClose"
>
<div>渲染表单</div>
<span>我是内容部分 </span>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="dialogVisible = false">
确认
</el-button>
</div>
</template>
</el-dialog>
</template>
ArticleChannel.vue
<script setup>
import { artGetChannelsService } from '@/api/article'
import { Delete,Edit } from '@element-plus/icons-vue'
import {ref} from 'vue'
import ChannelEdit from './components/ChannelEdit.vue'
const channelList = ref([]) // 文章分类列表
const loading = ref(false) //加载状态
const dialog = ref()
// 获取文章分类列表
const getChannelList = async () => {
// 发请求之前先将loading设置为true
loading.value = true
// 调用接口
const res = await artGetChannelsService()
channelList.value = res.data.data
// channelList.value = []
// 发完请求,关闭loading
loading.value = false
// console.log('文章分类列表',channelList.value);
}
// 调用获取文章分类列表
getChannelList()
// 编辑文章分类
const onEditChannel =(row) =>{
// console.log(row,$index)
dialog.value.open({row})
}
// 删除文章分类
const onDelChannel =(row,$index)=>{
console.log(row,$index)
}
const onAddChannel = () => {
dialog.value.open({})
}
</script>
<template>
<div>
<!-- 按需引入 -->
<page-container title="文章分类">
<!-- 右侧按钮 - 添加文章 - 具名插槽 -->
<template #extra>
<el-button @click="onAddChannel">添加分类</el-button>
</template>
<!-- 主体部分--表格 -->
<el-table :data="channelList" style="width: 100%" v-loading="loading">
<el-table-column label="序号" type="index" width="100" ></el-table-column>
<el-table-column label="分类名称" prop="cate_name" ></el-table-column>
<el-table-column label="分类别名" prop="cate_alias" ></el-table-column>
<el-table-column label="操作" width="100">
<template #default="{row,$index}">
<el-button @click="onEditChannel(row,$index)" plain :icon="Edit" circle type="primary" ></el-button>
<el-button @click="onDelChannel(row,$index)" plain :icon="Delete" circle type="danger" ></el-button>
</template>
</el-table-column>
<!-- 没有数据 -->
<template #empty>
<el-empty description="暂无数据"></el-empty>
</template>
</el-table>
<!-- 添加分类弹窗 -->
<channel-edit ref="dialog"> </channel-edit>
</page-container>
</div>
</template>
<style lang="scss" scoped>
</style>
预览视图
准备弹层表单
- 准备数据 和 校验规则
const formModel = ref({
cate_name: '',
cate_alias: ''
})
const rules = {
cate_name: [
{ required: true, message: '请输入分类名称', trigger: 'blur' },
{
pattern: /^\S{1,10}$/,
message: '分类名必须是1-10位的非空字符',
trigger: 'blur'
}
],
cate_alias: [
{ required: true, message: '请输入分类别名', trigger: 'blur' },
{
pattern: /^[a-zA-Z0-9]{1,15}$/,
message: '分类别名必须是1-15位的字母数字',
trigger: 'blur'
}
]
}
- 准备表单
<el-form
:model="formModel"
:rules="rules"
label-width="100px"
style="padding-right: 30px"
>
<el-form-item label="分类名称" prop="cate_name">
<el-input
v-model="formModel.cate_name"
minlength="1"
maxlength="10"
></el-input>
</el-form-item>
<el-form-item label="分类别名" prop="cate_alias">
<el-input
v-model="formModel.cate_alias"
minlength="1"
maxlength="15"
></el-input>
</el-form-item>
</el-form>
- 编辑需要回显,表单数据需要初始化
const open = async (row) => {
dialogVisible.value = true
formModel.value = { ...row }
//不回显的话,需要修改为
// formModel.value = {...row.row} 即可
}
- 基于传过来的表单数据,进行标题控制,有 id 的是编辑
:title="formModel.id ? '编辑分类' : '添加分类'"
确认提交
api/article.js
封装请求 API
// 添加文章分类
export const artAddChannelService = (data) => request.post('/my/cate/add', data)
// 编辑文章分类
export const artEditChannelService = (data) =>
request.put('/my/cate/info', data)
- 页面中校验,判断,提交请求
<el-form ref="formRef">
const formRef = ref()
const onSubmit = async () => {
await formRef.value.validate()
formModel.value.id
? await artEditChannelService(formModel.value)
: await artAddChannelService(formModel.value)
ElMessage({
type: 'success',
message: formModel.value.id ? '编辑成功' : '添加成功'
})
dialogVisible.value = false
}
- 通知父组件进行回显
const emit = defineEmits(['success'])
const onSubmit = async () => {
...
emit('success')
}
- 父组件监听 success 事件,进行调用回显
<channel-edit ref="dialog" @success="onSuccess"></channel-edit>
const onSuccess = () => {
getChannelList()
}
源码
ChannelEdit.vue
<script setup>
import {ref} from 'vue'
const dialogVisible = ref(false) //弹层状态
// 组件对外暴露一个方法,open ,基于open 传来的参数,区分添加还是编辑
// open ({}) => 表单无需渲染,说明是添加分
// open ({id, name}) => 表单需要渲染,说明是编辑分类
// open调用后,可以打开弹窗
const open = async (row) =>{
// console.log(row)
dialogVisible.value = true
formModel.value = {...row.row} //添加 =》 重置了表单内容,编辑-> 存储了需要回显的数据
console.log('formModel:',formModel.value)
console.log(formModel.value.row.cate_name)
}
// 向外暴露一个方法,close,关闭弹窗
defineExpose({
open
})
const formModel = ref({
cate_name:'',
cate_alias:'' //别名
})
// 表单校验规则
const rules ={
cate_name:[
{required:true,message:'请输入分类名称',trigger:'blur'},
{pattern:/^\S{1,10}$/,message:'分类名称长度在1-10个字符之间',trigger:'blur'}
],
cate_alias:[
{required:true,message:'请输入分类别名',trigger:'blur'},
{pattern:/^[a-zA-Z0-9]{1,15}$/,message:'分类名称长度在1-15个字母或数字之间',trigger:'blur'}
]
}
// 表单提交
import { artEditChannelService,artAddChannelService } from '@/api/article'
// import { ElMessage } from 'element-plus';
const formRef = ref()
const emit = defineEmits(['success'])
const onSubmit = async () => {
await formRef.value.validate()
const isEdit = formModel.value.id
if(isEdit){
// 编辑
await artEditChannelService(formModel.value)
ElMessage.success('编辑成功')
}
else {
// 添加
await artAddChannelService(formModel.value)
ElMessage.success('添加成功')
}
// 无论编辑成功还是添加成功都需要关闭弹窗
dialogVisible.value = false
emit('success',isEdit) // 触发父组件的success事件
}
</script>
<template>
<el-dialog
v-model="dialogVisible"
:title="formModel.id ? '编辑分类' : '添加分类'"
width="500"
:before-close="handleClose"
>
<!-- 渲染表单 -->
<el-form ref="formRef" :model="formModel" :rules="rules" label-width="100px" style="padding-right:30px ;">
<el-form-item label="分类名称" prop="cate_name" ><el-input v-model="formModel.cate_name" placeholder="请输入分类名称"></el-input></el-form-item>
<el-form-item label="分类别名" prop="cate_alias" ><el-input v-model="formModel.cate_alias" placeholder="请输入分类别名"></el-input></el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="onSubmit"> 确认 </el-button>
</div>
</template>
</el-dialog>
</template>
ArticleChannel.vue
<script setup>
import { artGetChannelsService } from '@/api/article'
import { Delete,Edit } from '@element-plus/icons-vue'
import {ref} from 'vue'
import ChannelEdit from './components/ChannelEdit.vue'
const channelList = ref([]) // 文章分类列表
const loading = ref(false) //加载状态
const dialog = ref()
// 获取文章分类列表
const getChannelList = async () => {
// 发请求之前先将loading设置为true
loading.value = true
// 调用接口
const res = await artGetChannelsService()
channelList.value = res.data.data
// channelList.value = []
// 发完请求,关闭loading
loading.value = false
// console.log('文章分类列表',channelList.value);
}
// 调用获取文章分类列表
getChannelList()
// 编辑文章分类
const onEditChannel =(row) =>{
// console.log(row,$index)
dialog.value.open({row})
}
// 删除文章分类
const onDelChannel =(row,$index)=>{
console.log(row,$index)
}
const onAddChannel = () => {
dialog.value.open({})
}
const onSuccess =()=>{
// 刷新文章分类列表
getChannelList()
}
</script>
<template>
<div>
<!-- 按需引入 -->
<page-container title="文章分类">
<!-- 右侧按钮 - 添加文章 - 具名插槽 -->
<template #extra>
<el-button @click="onAddChannel">添加分类</el-button>
</template>
<!-- 主体部分--表格 -->
<el-table :data="channelList" style="width: 100%" v-loading="loading">
<el-table-column label="序号" type="index" width="100" ></el-table-column>
<el-table-column label="分类名称" prop="cate_name" ></el-table-column>
<el-table-column label="分类别名" prop="cate_alias" ></el-table-column>
<el-table-column label="操作" width="100">
<template #default="{row,$index}">
<el-button @click="onEditChannel(row,$index)" plain :icon="Edit" circle type="primary" ></el-button>
<el-button @click="onDelChannel(row,$index)" plain :icon="Delete" circle type="danger" ></el-button>
</template>
</el-table-column>
<!-- 没有数据 -->
<template #empty>
<el-empty description="暂无数据"></el-empty>
</template>
</el-table>
<!-- 添加分类弹窗 -->
<channel-edit ref="dialog" @success="onSuccess"> </channel-edit>
</page-container>
</div>
</template>
<style lang="scss" scoped>
</style>
预览视图
文章分类删除
api/article.js
封装接口 api
// 删除文章分类
export const artDelChannelService = (id) =>
request.delete('/my/cate/del', {
params: { id }
})
- 页面中添加确认框,调用接口进行提示(
ArticleChannel.vue
)
const onDelChannel = async (row) => {
await ElMessageBox.confirm('你确认删除该分类信息吗?', '温馨提示', {
type: 'warning',
confirmButtonText: '确认',
cancelButtonText: '取消'
})
await artDelChannelService(row.id)
ElMessage({ type: 'success', message: '删除成功' })
getChannelList()
}
预览视图
文章分类模块完结,撒花儿~~***