一、实现菜单管理弹框的基本静态骨架
页面
<el-dialog
:before-close="cancel"
center
:title="isAdd ? '添加菜单' : '修改菜单'"
:visible.sync="isShow"
>
<el-form ref="menuForm" :model="menuForm" :rules="rules">
<el-form-item
:label-width="formLabelWidth"
label="菜单名称"
prop="title"
>
<el-input v-model="menuForm.title" autocomplete="off"></el-input>
</el-form-item>
<el-form-item :label-width="formLabelWidth" label="上级菜单" prop="pid">
<el-select v-model="menuForm.pid" placeholder="请选择上级菜单">
<el-option label="顶级菜单" :value="0"></el-option>
<el-option
v-for="item in menulist"
:key="item.id"
:label="item.title"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
<el-form-item :label-width="formLabelWidth" label="菜单类型">
<el-radio v-model="menuForm.type" :label="1">目录</el-radio>
<el-radio v-model="menuForm.type" :label="2">菜单</el-radio>
</el-form-item>
<el-form-item :label-width="formLabelWidth" label="菜单图标">
<el-input v-model="menuForm.icon" autocomplete="off"></el-input>
</el-form-item>
<el-form-item :label-width="formLabelWidth" label="菜单地址">
<el-input v-model="menuForm.url" autocomplete="off"></el-input>
</el-form-item>
<el-form-item :label-width="formLabelWidth" label="状态">
<el-switch
v-model="menuForm.status"
active-color="#13ce66"
inactive-color="#ff4949"
:active-value="1"
:inactive-value="2"
>
</el-switch>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="cancel">取 消</el-button>
<el-button type="primary" @click="comfirm">确 定</el-button>
</div>
</el-dialog>
js代码
// 引入封装好的接口
import { menuAdd, menuInfo, menuEdit } from "../../request/api";
//引入辅助性函数
import { mapActions, mapGetters } from "vuex";
export default {
data() {
return {
// 先声明一个菜单表单对象
menuForm: {
pid: 0, //上级分类编号 注意:顶级菜单-0
title: "", //菜单名称
icon: "", //图标
type: 1, //类型 1目录2菜单
url: "", //菜单地址
status: 1, //状态 1正常2禁用 number类型
},
formLabelWidth: "120px",
rules: {
title: [
// required必须的 必传项
{ required: true, message: "请输入菜单名称", trigger: "blur" },
{ min: 2, max: 6, message: "长度在 2 到 6 个字符", trigger: "blur" },
],
pid: [{ required: true, message: "请选择上级菜单", trigger: "change" }],
},
};
},
computed: {
...mapGetters({
menulist: "menu/getMenuList",
}),
},
props: ["isShow", "isAdd"],
methods: {
//获取一条数据的方法
lookup(id) {
console.log(id,'iiiiii');
menuInfo({
id,
}).then((res) => {
console.log(res, "一条数据");
this.menuForm = res.list;
this.menuForm.id = id;
});
},
...mapActions({
getMenu: "menu/changeMenuAction",
}),
//封装一个取消事件
cancel() {
this.$emit("cancel", false);
//调用重置事件
this.reset();
},
//封装一个重置事件
reset() {
//清空输入内容
this.menuForm = {
pid: 0, //上级分类编号 注意:顶级菜单-0
title: "", //菜单名称
icon: "", //图标
type: 1, //类型 1目录2菜单
url: "", //菜单地址
status: 1, //状态 1正常2禁用 number类型
};
//清空验证规则
// resetFields 对整个表单进行重置,将所有字段值重置为初始值并移除校验结果
this.$refs.menuForm.resetFields();
},
//封装一个确定事件
comfirm() {
this.$refs.menuForm.validate(async (flag) => {
console.log(flag);
if (flag) {
//通过属性isAdd去区分 区分是添加还是编辑
if (this.isAdd) {
//添加接口
// console.log(this.menuForm, "菜单的表单对象");
// console.log("添加");
let res = await menuAdd(this.menuForm);
// console.log(res, "添加菜单");
if (res.code == 200) {
this.$message.success(res.msg);
//添加成功之后关闭弹框
this.cancel();
//重新触发行动
this.getMenu();
} else {
this.$message.error(res.msg);
}
} else {
//调用编辑接口
console.log("编辑");
let res = await menuEdit(this.menuForm);
console.log(res, "添加菜单");
if (res.code == 200) {
this.$message.success(res.msg);
//添加成功之后关闭弹框
this.cancel();
//重新触发行动
this.getMenu();
} else {
this.$message.error(res.msg);
}
}
} else {
console.log("验证失败");
}
});
},
},
};
二、实现通过添加或者编辑打开不同的弹框
菜单页面
<template>
<div>
<!-- 面包屑导航 -->
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
<el-breadcrumb-item><a href="#">菜单管理</a></el-breadcrumb-item>
</el-breadcrumb>
<!-- 添加按钮 -->
<el-button @click="addDialog" plain class="btn" type="primary" size="small">添加</el-button>
<!-- 列表的渲染 -->
<v-list @edit="edit"></v-list>
<!-- 弹框组件 -->
<v-dialog ref='digInfo' :isAdd = 'isAdd' @cancel="cancel" :isShow = 'isShow'></v-dialog>
</div>
</template>
菜单逻辑
//引入list组件
import vList from './list.vue'
//引入弹框组件
import vDialog from './dialog.vue'
export default {
data() {
return {
isShow:false, //用于控制弹框的显示隐藏
isAdd:true //用来告知弹框是新增还是修改
};
},
components:{
vList,
vDialog
},
methods:{
//封装一个添加按钮事件,目的 打开弹框
addDialog(){
//打开弹框
this.isShow = true
//告诉弹框你是新增
this.isAdd = true
},
//子控制父 去关闭弹框
cancel(e){
this.isShow = e
},
//封装一个列表的自定义事件
edit(e){
//打开弹框
this.isShow = true
//告诉弹框你是编辑
this.isAdd = false
this.$refs.digInfo.lookup(e)
// console.log(e,'eeeeeeeee');
}
}
};
三、实现点击内容以及验证规则的重置 和实现点击删除按钮出现弹框
//封装一个重置事件
reset() {
//清空输入内容
this.menuForm = {
pid: 0, //上级分类编号 注意:顶级菜单-0
title: "", //菜单名称
icon: "", //图标
type: 1, //类型 1目录2菜单
url: "", //菜单地址
status: 1, //状态 1正常2禁用 number类型
};
//清空验证规则
// resetFields 对整个表单进行重置,将所有字段值重置为初始值并移除校验结果
this.$refs.menuForm.resetFields()
},
//封装一个删除事件
del() {
this.$confirm("你确定要删除这条数据吗", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
console.log('准备调用删除接口');
})
.catch(() => {
this.$message({
type: "info",
message: "已取消删除",
});
});
},
四、有大量的接口,封装一个接口文件
// 引入核心库
import axios from "axios";
//通过querystring去进行转化
import qsString from 'querystring'
//设置基础地址
let baseUrl = "/api";
//拦截器之请求拦截器
axios.interceptors.request.use((req) => {
return req;
});
//拦截器之响应拦截器
axios.interceptors.response.use((res) => {
return res.data;
});
/*
全局封装get 方法
url 地址
params参数
*/
export const get = (url, params = {}) => {
return new Promise((resolve, reject) => {
//调用axios中的get方法
axios
.get(baseUrl + url, {
params,
})
.then((res) => {
resolve(res);
})
.catch((err) => {
reject(err);
});
});
};
/*
封装post方法
url 地址
params参数
isFile 是否含有上传文件
*/
/*
表单提交(post方式比较特殊)
content-type
值 描述
application/x-www-form-urlencoded 在发送前编码所有字符(默认)
multipart/form-data
不对字符编码。
在使用包含文件上传控件的表单时,必须使用该值。
*/
export const post = (url, params = {}, isFile = false) => {
let data = {}
if(isFile){
data = new FormData()
for(let i in params){
data.append(i,params[i])
}
}else{
data = qsString.stringify(params)
// data=params
}
return new Promise((resolve, reject) => {
axios
.post(baseUrl + url, data)
.then((res) => {
resolve(res);
})
.catch((err) => {
reject(err);
});
});
};
//引入封装好的方法
import {get,post} from './index'
/* =============菜单管理=============== */
// 封装一个菜单添加的接口
export const menuAdd = data=>post('/menuadd',data)
五、实现菜单的添加接口调用
this.$refs.menuForm.validate(async (flag) => {
console.log(flag);
if (flag) {
//通过属性isAdd去区分 区分是添加还是编辑
if (this.isAdd) {
//添加接口
// console.log(this.menuForm, "菜单的表单对象");
// console.log("添加");
let res = await menuAdd(this.menuForm);
// console.log(res, "添加菜单");
if(res.code==200){
this.$message.success(res.msg)
//添加成功之后关闭弹框
this.cancel()
}else{
this.$message.error(res.msg)
}
} else {
//调用编辑接口
console.log("编辑");
}
} else {
console.log("验证失败");
}
});
六、把列表拆分出去,因为添加,编辑,删除成功之后都需要重新获取列表,就是有很多地方都用到这个列表,然后把放到vuex中
注意:
当我们添加、编辑、删除成功之后我们要重新获取列表,同时添加菜单的上级菜单列表也要用到列表接口
我们发现很多组件和方法都用到了这个列表,我们准备把它放置在vuex中
//引入封装好的接口
import { menuList } from "../../../request/api";
const state = {
menulist: [],
};
const getters = {
getMenuList(state) {
return state.menulist;
},
};
const mutations = {
REQ_MENULIST(state,payload){
state.menulist = payload
}
};
const actions = {
async changeMenuAction({commit}) {
let res = await menuList();
// console.log(res, "菜单列表");
commit('REQ_MENULIST',res.list)
},
};
export default {
state,
getters,
mutations,
actions,
//命名空间
namespaced: true,
};
import Vue from 'vue'
import Vuex from 'vuex'
import menu from './modules/menu'
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
menu
}
})
在页面中使用vuex
//辅助性函数
import {mapGetters,mapActions} from 'vuex'
export default {
computed:{
...mapGetters({
getMenu:'menu/getMenuList'
})
},
mounted() {
this.getMenuList();
},
methods: {
...mapActions({
getMenuList:'menu/changeMenuAction'
}),
//封装一个编辑事件用来告知父组件打开弹框
edit() {
this.$emit("edit");
},
//封装一个删除事件
del() {
this.$confirm("你确定要删除这条数据吗", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
console.log("准备调用删除接口");
})
.catch(() => {
this.$message({
type: "info",
message: "已取消删除",
});
});
},
},
};
七、table树形结构
<el-table row-key="id"
:tree-props="{children: 'children'}"
default-expand-all
:data="getMenu" border style="width: 100%">
row-key 行数据的 Key,用来优化 Table 的渲染;在使用 reserve-selection 功能与显示树形数据时,该属性是必填的。类型为 String 时,支持多层访问:user.info.id,但不支持 user.info[0].id,此种情况请使用 Function。
default-expand-all 是否默认展开所有行,当 Table 包含展开行存在或者为树形表格时有效
tree-props 渲染嵌套数据的配置选项
八、实现删除接口
menuDel({
id,
}).then((res) => {
if (res.code == 200) {
this.$message.success(res.msg);
//重新触发行动
this.getMenuList();
} else {
this.$message.error(res.msg);
}
});
九、编辑数据回显
list页面
//通过点击事件,然后子传父($emit),把id传过去
edit(id) {
this.$emit("edit",id);
},
menu逻辑
//封装一个列表的自定义事件
edit(e){
//打开弹框
this.isShow = true
//告诉弹框你是编辑
this.isAdd = false
// 通过ref 也可以控制子组件的事件,用子组件的封装好的回显函数
this.$refs.digInfo.lookup(e)
// console.log(e,'eeeeeeeee');
}
弹框逻辑
//获取一条数据的方法
lookup(id) {
传过来的id
// console.log(id,'iiiiii');
// 调用单条数据的接口
menuInfo({
id,
}).then((res) => {
console.log(res, "一条数据");
this.menuForm = res.list;
this.menuForm.id = id;
});
},
十、实现编辑接口的调用
//调用编辑接口
console.log("编辑");
let res = await menuEdit(this.menuForm);
// console.log(res, "添加菜单");
if (res.code == 200) {
this.$message.success(res.msg);
//添加成功之后关闭弹框
this.cancel();
//重新触发行动
this.getMenu();
} else {
this.$message.error(res.msg);
}