一. 文章分类页面 - [element-plus 表格]
功能需求说明:
(1). 基本架子- PageContainer 封装
(2). 文章分类渲染&loading 处理
(3). 文章分类添加编辑[element-plus 弹层]
(4). 文章分类删除
1. 定义公共 静态页面结构
src\components\PageContainer.vue
<script setup>
defineProps({
title: {
required: true,
type: String
}
})
</script>
<template>
<el-card class="page-container">
<template #header>
<div class="header">
<span>{{ title }}</span>
<div class="extra">
<!-- 右侧按钮: 使用具名插槽 -->
<slot name="extra"></slot>
</div>
</div>
</template>
<!-- 插槽定义内容 -->
<slot></slot>
</el-card>
</template>
<style lang="scss" scoped>
.page-container {
min-height: 100%;
box-sizing: border-box;
.header {
display: flex;
align-items: center;
justify-content: space-between;
}
}
</style>
2. 文章分类组件调用公共组件
src\views\article\AtricleChannel.vue
<template>
<!-- 可以直接使用components里的公共组件-->
<page-container title="文章分类">
<!-- 具名插槽 -->
<template #extra>
<el-button>添加分类</el-button>
</template>
<!-- 普通插槽内容 -->
主题部分,是表格
</page-container>
</template>
<style lang="scss" scoped></style>
3. 文章管理组件调用公共组件
src\views\article\AtricleManage.vue
<template>
<!-- 可以直接使用components里的组件-->
<page-container title="文章管理">
<!-- 具名插槽 -->
<template #extra>
<el-button>添加文章</el-button>
</template>
<!-- 普通插槽内容 -->
主题部分,是表格 + 分页
</page-container>
</template>
<style lang="scss" scoped></style>
二. 文章分类渲染
1. 封装获取文章分类api
src\api\article.js
import request from '@/utils/request'
// 获取文章分类
export const artGetChannelService = () => request.get('/my/cate/list')
2. 页面中调用接口获取分类数据
src\views\article\AtricleChannel.vue
<script setup>
import { ref } from 'vue'
import { artGetChannelService } from '../../api/article'
const channelList = ref([])
const getChannlList = async () => {
const res = await artGetChannelService() // 调用api
channelList.value = res.data.data
console.log(channelList.value)
}
getChannlList() // 一进页面直接调用
</script>
3. el-table 表格动态渲染数据
src\views\article\AtricleChannel.vue
<script>
...
//编辑和删除的点击事件
const onEditChannel = (row, $index) => {
console.log(row, $index)
}
const onDelChannel = (row, $index) => {
console.log(row, $index)
}
</script>
<template>
...
<!-- 普通插槽内容 -->
<el-table :data="channelList" style="width: 100%">
<el-table-column type="index" label="序号" width="100"> </el-table-column>
<el-table-column prop="cate_name" label="分类名称"> </el-table-column>
<el-table-column prop="cate_alias" label="分类别名"> </el-table-column>
<el-table-column label="操作" width="150">
<!-- row 就是 channelList的一项, $index 下标 -->
<template #default="{ row, $index }">
<el-button
:icon="Edit"
circle
plain
type="primary"
@click="onEditChannel(row, $index)"
></el-button>
<el-button
:icon="Delete"
circle
plain
type="danger"
@click="onDelChannel(row, $index)"
></el-button>
</template>
</el-table-column>
<!--空状态组件-->
<template #empty>
<el-empty description="没有数据"></el-empty>
</template>
</el-table>
</template>
4. el-table 表格 添加loading 效果
src\views\article\AtricleChannel.vue
<script>
// 定义默认loading状态
const loading = ref(false)
...
const getChannlList = async () => {
loading.value = true // 发送请求前开启
const res = await artGetChannelService() // 调用api
channelList.value = res.data.data
loading.value = false // 结束请求后关闭
}
...
</script>
<template>
<!-- 普通插槽内容 -->
<el-table v-loading="loading" ...>
...
</el-table>
</template>
三. 添加分类-显示弹层
1. 封装弹层组件
src\views\article\components\ChannelEdit.vue
<script setup>
import { ref } from 'vue'
const dialogVisible = ref(false)
// 组件对外暴露一个方法 open,基于open传来的参数,区分添加还是编辑
// open({}) => 表单无需渲染,说明是添加
// open({ id, cate_name,...}) => 表单需要渲染,说明是编辑
// open 调用后,可以打开弹窗
const open = (row) => {
console.log(row)
dialogVisible.value = true
}
// 向外暴露方法
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" @click="dialogVisible = false">
确认
</el-button>
</span>
</template>
</el-dialog>
</template>
2. 文章分类调用弹层组件
src\views\article\AtricleChannel.vue
<script>
import ChannelEdit from './components/ChannelEdit.vue' // 导入弹层组件
...
const dialog = ref()
...
// 编辑,调用方法显示弹层
const onEditChannel = (row) => {
dialog.value.open(row)
}
// 添加,调用方法显示弹层
const onAddChannel = () => {
dialog.value.open({})
}
</script>
<template>
<page-container title="文章分类">
<!-- 具名插槽 -->
<template #extra>
<el-button @click="onAddChannel">添加分类</el-button>
</template>
<!-- 普通插槽内容 -->
<el-table>
<el-button :icon="Edit"... @click="onEditChannel(row, $index)"></el-button>
</el-table>
<!--弹层组件,获取组件-->
<channel-edit ref="dialog"></channel-edit>
</page-container>
</template>
四. 添加分类-添加完成
1. 弹层组件准备数据 和 校验规则
src\views\article\components\ChannelEdit.vue
<script setup>
...
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'
}
]
}
...
</script>
2. 准备表单绑定校验
src\views\article\components\ChannelEdit.vue
<template>
<el-dialog v-model="dialogVisible" title="添加弹层" width="30%">
<!-- 内容改为form表单 -->
<!--1. el-form绑定formModel数据对象 和 rules校验对象-->
<el-form
:model="formModel"
:rules="rules"
lable-width="100px"
style="padding-right: 30px"
>
<!--2.el-form-item 直接绑定属性-->
<el-form-item label="分类名称" prop="cate_name">
<!--3.el-input 绑定数据对象中的属性-->
<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>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="dialogVisible = false">
确认
</el-button>
</span>
</template>
</el-dialog>
</template>
3. 回显数据
src\views\article\components\ChannelEdit.vue
<script setup>
...
const open = (row) => {
dialogVisible.value = true
formModel.value = { ...row } // 添加 -> 重置了表单内容, 编辑 -> 存储了需要回显的数据
}
...
</script>
<template>
<!--基于传过来的表单数据,进行标题控制,有 id 的是编辑-->
<el-dialog
v-model="dialogVisible"
:title="formModel.id ? '编辑分类' : '添加分类'"
width="30%"
>
</template>
4. 提交确认
(1). 封装提交api
src\api\article.js
import request from '@/utils/request'
...
// 添加文章分类
export const artAddChannelService = (data) => request.post('/my/cate/add', data)
// 编辑文章分类
export const artEditChannelService = (data) =>
request.put('/my/cate/info', data)
(2). 页面中预校验提交请求
src\views\article\components\ChannelEdit.vue
<script>
import { artEditChannelService, artAddChannelService } from '@/api/article.js'
...
// 定义formRef
const formRef = ref()
...
const onSubmit = async () => {
await formRef.value.validate() // 校验表单
const isEdit = formModel.value.id // 尝试获取id
if (isEdit) {
// 能获取到id 就是编辑分类
await artEditChannelService(formModel.value)
ElMessage.success('编辑成功')
} else {
//添加分类
await artAddChannelService(formModel.value)
ElMessage.success('添加成功')
}
// 关闭弹层
dialogVisible.value = false
}
...
</script>
<template>
<!-- ref获取表单 -->
<el-form ref="formRef" ... >...</el-form>
<!--确认按钮定义点击事件-->
<el-button type="primary" @click="onSubmit"> 确认 </el-button>
</template>
(3) .通知父组件刷新页面数据
src\views\article\components\ChannelEdit.vue
<script>
// 定义子传父事件,通知父组件刷新页面数据
const emit = defineEmits(['success'])
const onSubmit = async () => {
...
// 关闭弹层
dialogVisible.value = false
emit('success') // 父子通信
}
</script>
(4). 父组件接收通知,刷新数据
src\views\article\AtricleChannel.vue
<script>
...
// 重新调用获取分类api
const onSuccess = () => {
getChannlList()
}
</script>
<template>
<!--监听事件: success,进行调用回显-->
<channel-edit ref="dialog" @success="onSuccess"></channel-edit>
</template>
五. 文章分类删除
1. 封装删除api
src\api\article.js
import request from '@/utils/request'
...
//删除文章分类
export const artDelChannelService = (id) =>
request.delete('/my/cate/del', {
params: { id }
})
2. 页面中调用删除接口
src\views\article\AtricleChannel.vue
<script>
import { artGetChannelService, artDelChannelService } from '../../api/article'
...
//删除
const onDelChannel = async (row) => {
await ElMessageBox.confirm('你确认删除该分类信息吗?', '温馨提示', {
type: 'warning',
confirmButtonText: '确认',
cancelButtonText: '取消'
})
await artDelChannelService(row.id) // 调用删除api
ElMessage.success('删除成功')
getChannlList() // 重新调用获取数据接口渲染数据
}
</script>