1.菜单服务
1.1连接登录服务接口
①.导入sql文件
1.选中数据库test,右键选择运行SQL文件
2.选中路径导入

3.刷新页面
pn_admin_menu 菜单表

有一级菜单和二级菜单,主菜单和副菜单的属性很相似,故在一个表。
pn_admin_user 用户表

看一下sql语句:
登录成功之后会先找用户的权限字段:

找到该用户对应的权限菜单:

权限字段拿到之后,会通过它查一级和二级菜单(一般不会超过二级),最后返回给页面的是嵌套的数据。但这样的数据,数据库给不了。
现在先查一级菜单:

查一级菜单,也就是pid=0 对应的sql语句:select * from pn_admin_menu pam WHERE pam.pid
二级菜单:select * from pn_admin_menu pam WHERE pam.pid != 0
现在是查用户有的菜单:
如下是匹配的二级菜单:

拿到登录成功的用户的一级菜单就可以遍历,找对应的二级菜单,然后塞进一级菜单。
②.导入后台服务接口

导入的项目会重新创建一个项目,项目名这里用smStep2

设置环境:

引入项目的依赖:

选择Library,选择Tomcat运行环境:

其他服务接口继承BaseServlet。
这里的过滤器主要允许跨域请求和登录效验。
先把服务跑起来:

点击+号后,选择Tomcat Serve里的Local,添加Tomcat实例。
创建Artifacts:


选择完之后,点击ok
加载当前的项目:

运行服务器。
试试这几个服务接口有没有问题:
先访问登录服务:http://localhost:8080/login?username=abc&pwd=abc
页面显示 {"returnCode":20001,"returnMsg":"用户名或密码错误"}
访问:http://localhost:8080/login?username=%E6%B5%8B%E8%AF%951&pwd=abc123
页面显示 {"returnCode":10000,"returnMsg":"操作成功"}
登录成功后,登录接口会将当前用户登录信息和用户权限信息放到session。
//登录访问控制
session.setAttribute("loginUser", loginUser);
//权限访问控制 展示菜单
session.setAttribute("userRoles", userRole);
然后需要取用户session信息时,取出来拼成json格式给界面返回。(GetMenuServlet接口)
访问:http://localhost:8080/getmenu
页面显示:
{"returnCode":10000,"returnData":[{"glyphicon":"el-icon-user","menuid":11,"menuname":"管理中心","menuurl":"#","pid":0,"pname":"","submenu":[{"glyphicon":"glyphicon glyphicon-lock","menuid":11001,"menuname":"用户管理","menuurl":"/users","pid":11,"pname":"","submenu":[]},{"glyphicon":"glyphicon glyphicon-lock","menuid":11002,"menuname":"菜单管理","menuurl":"/menus","pid":11,"pname":"","submenu":[]}]},{"glyphicon":"el-icon-s-order","menuid":12,"menuname":"模版管理","menuurl":"#","pid":0,"pname":"","submenu":[{"glyphicon":"","menuid":12001,"menuname":"模版配置","menuurl":"/template/cfglist","pid":12,"pname":"","submenu":[]},{"glyphicon":"","menuid":12002,"menuname":"模版列表","menuurl":"/template/templatelist","pid":12,"pname":"","submenu":[]}]},{"glyphicon":"el-icon-data-line","menuid":13,"menuname":"广告管理","menuurl":"#","pid":0,"pname":"","submenu":[{"glyphicon":"","menuid":13001,"menuname":"首页置顶广告","menuurl":"/banner/toplist","pid":13,"pname":"","submenu":[]}]},{"glyphicon":"el-icon-timer","menuid":14,"menuname":"游戏管理","menuurl":"#","pid":0,"pname":"","submenu":[{"glyphicon":"glyphicon glyphicon-eye-close","menuid":14001,"menuname":"游戏配置","menuurl":"/game/gamelist","pid":14,"pname":"","submenu":[]}]},{"glyphicon":"el-icon-ship","menuid":15,"menuname":"合作公司管理","menuurl":"#","pid":0,"pname":"","submenu":[{"glyphicon":"glyphicon glyphicon-send","menuid":15001,"menuname":"合作公司管理","menuurl":"/partner/list","pid":15,"pname":"","submenu":[]}]},{"glyphicon":"el-icon-setting","menuid":16,"menuname":"渠道版本","menuurl":"#","pid":0,"pname":"","submenu":[{"glyphicon":"glyphicon glyphicon-screenshot","menuid":16001,"menuname":"渠道管理","menuurl":"/channel/list","pid":16,"pname":"","submenu":[]},{"glyphicon":"glyphicon glyphicon-bullhorn","menuid":16002,"menuname":"渠道分类管理","menuurl":"/channel/typelist","pid":16,"pname":"","submenu":[]}]}],"returnMsg":"操作成功"}
新建测试类MyTest:
按照①.的设想,写一下代码:
public class MyTest {
public static void main(String[] args) {
LoginDao ld = new LoginDaoImpl();
//查询用户的权限信息 11001,11002,12001,12002,12003,13001,14001,14002,15001,16001,16002,19001,19002,11,12,13,14,15,16
User user = new User();
user.setUserId(9);
String userRole = ld.getUserRole(user);
MenuDao md = new MenuDaoImpl();
//查一级菜单
List<Menu> lm1 = md.getMenuByLevel(0,userRole);
//查二级菜单
List<Menu> lm2 = md.getMenuByLevel(1,userRole);
System.out.println(lm1);
System.out.println(lm2);
System.out.println("------------------------------------");
for (Menu menu1:lm1){ //遍历一级菜单
for(Menu menu2:lm2){ //遍历二级菜单
if(menu2.getPid().equals(menu1.getPid())){ //若二级菜单能和一级菜单匹配
menu1.getSubmenu().add(menu2); //将当前二级菜单塞进去
}
}
}
System.out.println(lm1);
}
}
控制台输出:
select mu.mid,mu.menuname,mu.pid,mu.url,mu.glyphicon from pn_admin_menu mu where mu.pid=0 and mu.mid in (11001,11002,12001,12002,12003,13001,14001,14002,15001,16001,16002,19001,19002,11,12,13,14,15,16)
select mu.mid,mu.menuname,mu.pid,mu.url,mu.glyphicon from pn_admin_menu mu where mu.pid!=0 and mu.mid in (11001,11002,12001,12002,12003,13001,14001,14002,15001,16001,16002,19001,19002,11,12,13,14,15,16)
[Menu{menuid=11, menuname='管理中心', menuurl='#', pid=0, pname='', glyphicon='el-icon-user', submenu=[]}, Menu{menuid=12, menuname='模版管理', menuurl='#', pid=0, pname='', glyphicon='el-icon-s-order', submenu=[]}, Menu{menuid=13, menuname='广告管理', menuurl='#', pid=0, pname='', glyphicon='el-icon-data-line', submenu=[]}, Menu{menuid=14, menuname='游戏管理', menuurl='#', pid=0, pname='', glyphicon='el-icon-timer', submenu=[]}, Menu{menuid=15, menuname='合作公司管理', menuurl='#', pid=0, pname='', glyphicon='el-icon-ship', submenu=[]}, Menu{menuid=16, menuname='渠道版本', menuurl='#', pid=0, pname='', glyphicon='el-icon-setting', submenu=[]}]
[Menu{menuid=11001, menuname='用户管理', menuurl='/users', pid=11, pname='', glyphicon='glyphicon glyphicon-lock', submenu=[]}, Menu{menuid=11002, menuname='菜单管理', menuurl='/menus', pid=11, pname='', glyphicon='glyphicon glyphicon-lock', submenu=[]}, Menu{menuid=12001, menuname='模版配置', menuurl='/template/cfglist', pid=12, pname='', glyphicon='', submenu=[]}, Menu{menuid=12002, menuname='模版列表', menuurl='/template/templatelist', pid=12, pname='', glyphicon='', submenu=[]}, Menu{menuid=13001, menuname='首页置顶广告', menuurl='/banner/toplist', pid=13, pname='', glyphicon='', submenu=[]}, Menu{menuid=14001, menuname='游戏配置', menuurl='/game/gamelist', pid=14, pname='', glyphicon='glyphicon glyphicon-eye-close', submenu=[]}, Menu{menuid=15001, menuname='合作公司管理', menuurl='/partner/list', pid=15, pname='', glyphicon='glyphicon glyphicon-send', submenu=[]}, Menu{menuid=16001, menuname='渠道管理', menuurl='/channel/list', pid=16, pname='', glyphicon='glyphicon glyphicon-screenshot', submenu=[]}, Menu{menuid=16002, menuname='渠道分类管理', menuurl='/channel/typelist', pid=16, pname='', glyphicon='glyphicon glyphicon-bullhorn', submenu=[]}, Menu{menuid=19001, menuname='标签列表', menuurl='/tag/taglist', pid=19, pname='', glyphicon='glyphicon glyphicon-tags', submenu=[]}]
------------------------------------
[Menu{menuid=11, menuname='管理中心', menuurl='#', pid=0, pname='', glyphicon='el-icon-user', submenu=[]}, Menu{menuid=12, menuname='模版管理', menuurl='#', pid=0, pname='', glyphicon='el-icon-s-order', submenu=[]}, Menu{menuid=13, menuname='广告管理', menuurl='#', pid=0, pname='', glyphicon='el-icon-data-line', submenu=[]}, Menu{menuid=14, menuname='游戏管理', menuurl='#', pid=0, pname='', glyphicon='el-icon-timer', submenu=[]}, Menu{menuid=15, menuname='合作公司管理', menuurl='#', pid=0, pname='', glyphicon='el-icon-ship', submenu=[]}, Menu{menuid=16, menuname='渠道版本', menuurl='#', pid=0, pname='', glyphicon='el-icon-setting', submenu=[]}]
之前submenu是空的,现在就有了数据了。

最后只需做格式转换,然后把这样的菜单数据返回给前端,前端就可以遍历使用了。
③.使用postman
信息太多,用postman工具。
新建集合:

起名newtest。
新建项目,new后选择Request:

点击确定。

点击send。
控制台输出:{"returnCode":10000,"returnMsg":"操作成功"}
新建queryUserMenu项目:

submenu里放的子菜单数据。配合前端的vue,两层v-for循环就可将数据遍历出来。
第二个服务接口GetMenuServlet作用:取登录的时候查出来的菜单数据。菜单数据的组织是在登录时就已经放好,登录成功后直接从session里拿。
后端剩下的就是用户模块和菜单模块的增删改查。
新建queryMenu(菜单模块查询):

可传page去翻页:http://localhost:8080/menu/query?page=2
再测试一下菜单的增加功能:

对应的数据库里,菜单表多了一条数据。
后台服务接口已经开发结束,接下来是前端。
④.前端部分
打开视图界面工具可访问:http://localhost:8000/dashboard
打开HBUilder,将配置文件的路由改为打开页面先显示登录页面:
{path:'/',redirect:"/login"}
现在要使前端的登录和后台登录服务接口真正结合起来:
回到登录组件loginPage.vue:
如果验证成功,发Ajax请求去后台。找到后台登录服务接口地址(从postman复制,建的第一个项目就是登录),填入。
现在是跨域访问,需要绝对路径。
发送的参数要和后台搭配起来,后台用的是username和pwd。
同时数据是从界面拿过来的,且拿过来之后用qs转一下再发送
<template>
<div>
<el-card class="box-card mycard">
<div slot="header" class="clearfix">
<span>登录</span>
</div>
<div class="text item">
<el-form ref="myform" :rules="rules" :model="form" label-width="80px" hide-required-asterisk>
<el-form-item label="用户名" prop="username">
<el-input v-model="form.username" suffix-icon="el-icon-user"></el-input>
</el-form-item>
<el-form-item label="密码" prop="pwd">
<el-input v-model="form.pwd" show-password suffix-icon="el-icon-lock"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="mySubmit()">登录</el-button>
<el-button @click="resetForm()">重置</el-button>
</el-form-item>
</el-form>
</div>
</el-card>
</div>
</template>
<script>
export default {
methods: {
mySubmit(){
//$refs 注册给vue的组件
console.log(this);
this.$refs['myform'].validate((valid) => {
if (valid) {
console.log("提交数据");
console.log(this.$qs.stringify(this.form));
//跨域访问用绝对路径,参数要和后端匹配。同时数据是从界面拿过来的,且拿过来之后用qs转一下再发送
console.log(this.$axios.get("http://localhost:8080/login?"+this.$qs.stringify(this.form))
.then((ret)=>{
console.log(ret);
})
.catch((err)=>{
console.log(err); //若有错误,打印出来
}));
} else {
console.log('数据有误 不能提交');
return false;
}
});
},
resetForm(formName) {
this.$refs['myform'].resetFields(); //通过this.$refs['myform']找到组件,调用resetFields方法清空数据
}
},
data () {
return {
form: {
username: '',
pwd:''
},
rules: {
pwd: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, max: 8, message: '长度在 6 到 8 个字符', trigger: 'blur' }
]
}
};
}
}
</script>
<style>
.text {
font-size: 14px;
}
.item {
margin-bottom: 18px;
}
.clearfix:before,
.clearfix:after {
display: table;
content: "";
}
.clearfix:after {
clear: both
}
.box-card {
width: 480px;
}
.mycard{
margin:240px auto;
}
</style>
同时后端的登录服务接口也要允许它的跨域访问,修改一下:
跨域访问功能移到了过滤器,CheckLogin类:
resp.setHeader("Access-Control-Allow-Origin", "http://localhost:8088");
再检查一下前端服务器地址:

测试:
登录界面先来一个错的:
用户名:abcabc
密码:123456

(Header请求头和响应头 Payload给后端传递的参数
Preview后端返回的参数 Response后台返回的响应)
返回的响应是:{"returnCode":20001,"returnMsg":"用户名或密码错误"}
再来个正确的:
用户名:测试1
密码:abc123
返回的响应:{"returnCode":10000,"returnMsg":"操作成功"}
至此跨域访问成功。
如果用户名或者密码错误,要有一个体现,让用户知道。
⑤.使用elementUI
组件里Notice部分的Message部分的不同状态。
this.$message.error('错了哦,这是一条错误消息');
在组件里添加:
.then((ret)=>{
console.log(ret);
if(ret.data.returnCode == 20001){
this.$message.error(returnMsg);
}
})
最后用户名密码正确则跳转到main组件。
.then((ret)=>{
console.log(ret);
if(ret.data.returnCode == 20001){
this.$message.error(ret.data.returnMsg);
}else if(ret.data.returnCode == 10000){
this.$router.push("/main");
}
})
使用脚手架之后,前端项目和后端项目完全隔离开了。
前端服务和后端服务之间没什么关联,就是两套应用程序通过http的异步请求做数据交互。
每个组件访问后端都要写完整的访问路径,很麻烦,axios提供了新的方法。(官网可看)
后台通过cookie保存浏览器和它的对应关系,故往后台发消息时,cookie也要允许去发送。
在main.js,加全局配置:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import './plugins/element.js'
import qs from 'qs'
import axios from 'axios'
Vue.config.productionTip = false
/*为axios配置全局参数*/
//服务器路径
axios.defaults.baseURL="http://localhost:8080/"
//跨域带cookie
axios.defaults.withCredentials = true
Vue.prototype.$qs = qs;
Vue.prototype.$axios = axios
new Vue({
router,
render: h => h(App)
}).$mount('#app')
然后发ajax时:
this.$axios.get("/login?"+this.$qs.stringify(this.form))
1.2动态菜单 配合后台接口做访问控制(GetMenuServlet接口)
①.登录成功后,发送axios请求,去请求GetMenuServlet接口。
mainpage组件:
请求不需要参数。
先打印出数据看看:
mounted(){
console.log("页面加载结束后执行");
this.$axios.get("/getmenu")
.then((ret)=>{
console.log(ret);
})
.catch((err)=>{
console.log(err);
});
}
后台返回的数据:

假数据删除,留一个空集合:
data () {
return {
menuList:[]
};
}
从poetman里复制一组该集合,改一下key:
<!--给不同用户展示不同的菜单,主要功能点还是在后台,后台根据用户的权限给前台准备好查询菜单的服务接口-->
<el-submenu v-for="menu in menuList" :index="menu.menuid.toString()">
<template slot="title">
<i :class="menu.glyphicon"></i>
<span>{{menu.menuname}}</span>
</template>
<el-menu-item v-for="subm in menu.submenu" :index="subm.menuurl">{{subm.menuname}}</el-menu-item>
</el-submenu>
<!--
"glyphicon": "el-icon-user",
"menuid": 11,
"menuname": "管理中心",
"menuurl": "#",
"pid": 0,
"pname": "",
"submenu": [
{
"glyphicon": "glyphicon glyphicon-lock",
"menuid": 11001,
"menuname": "用户管理",
"menuurl": "/users",
"pid": 11,
"pname": "",
"submenu": []
},
{
"glyphicon": "glyphicon glyphicon-lock",
"menuid": 11002,
"menuname": "菜单管理",
"menuurl": "/menus",
"pid": 11,
"pname": "",
"submenu": []
}
]
-->
接下来将取回的数据遍历到页面:
mounted(){
console.log("页面加载结束后执行");
this.$axios.get("/getmenu")
.then((ret)=>{
console.log(ret);
if(ret.data.returnCode==10000){
this.menuList = ret.data.returnData;
}
})
.catch((err)=>{
console.log(err);
});
}
效果如下:

②.点击菜单后要换到对应的组件:
每个菜单有自己的url地址,后台存的访问地址实际是前端的组件地址。

如上,用户管理对应/users组件,菜单管理对应/menus组件。
故前端组件需要把他俩加上。
为方便管理,在components目录下新建controlCenter(管理中心)目录。里面放两个模块,新建menus.vue和users.vue
<template>
<div>
用户模块
</div>
</template>
<script>
</script>
<style>
</style>
<template>
<div>
菜单模块
</div>
</template>
<script>
</script>
<style>
</style>
点击对应菜单实际是往这两个模块跳。
先导入这两个组件,打开index.js:
import Users from '../components/controlCenter/menus.vue' import Menus from '../components/controlCenter/menus.vue'
并配上对应的路由,和后台保存的地址搭配起来:
{path:'/users',component:Users},
{path:'/menus',component:Menus},
先在浏览器访问这两个组件,看有没有问题。
接下来就做点击跳到这两个组件:
在elementUI里的导航菜单有vue-router模式
加一个router属性。
<el-col :span="24">
<el-menu
router
default-active="2"
class="el-menu-vertical-demo"
@open="handleOpen"
@close="handleClose"
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b">
<!--给不同用户展示不同的菜单,主要功能点还是在后台,后台根据用户的权限给前台准备好查询菜单的服务接口-->
<el-submenu v-for="menu in menuList" :index="menu.menuid.toString()">
<template slot="title">
<i :class="menu.glyphicon"></i>
<span>{{menu.menuname}}</span>
</template>
<el-menu-item v-for="subm in menu.submenu" :index="subm.menuurl">{{subm.menuname}}</el-menu-item>
</el-submenu>
此时,点击导航条的管理中心部分的用户管理和菜单管理,会跳到相应的组件。
③.配子路由
跳到用户或者菜单管理,也应该是上左右布局。每个组件里相同的内容都要写一遍。对于这种问题,还是路由解决。路由可配子路由,即在当前组件里替换某些部分,而不是整个替换。
之前在App.vue里
<template> <router-view></router-view> </template> <script> </script> <style> </style>
是所有的东西都替换到了根组件App.vue里。
若想替换部分:
在mainPage.vue要替换的地方加router-view标签,将
<el-main>Main</el-main>
改为:
<el-main> <router-view></router-view> </el-main>
然后配置路由时,配成子路由的形式:
{path:'/main',component:Main,children:[
{path:'/users',component:Users},
{path:'/menus',component:Menus}
]},
子路由就是来配合替换部分页面的。
此时效果:

④.加访问权限控制
后端有权限控制,前端却没有。
将后台服务器重启,登录信息没了。前端服务器访问菜单模块,后端返回响应,没有登录。
但前台可以随便敲,虽然后台数据不会给。

没有登录,应该返回登录页面,这样和后台就一致了。
在mainPage组件里:
.then((ret)=>{
console.log(ret);
if(ret.data.returnCode==10000){
this.menuList = ret.data.returnData;
}else if(ret.data.returnCode==20000){
this.$router.push("/login");
}
})
虽然现在是两个服务器了,但前端服务常配合后台服务接口做一些功能。
但是不是所有的请求都要加else if这样一个处理?即其他组件发ajax请求时是否也要看下有没有登录,做对应的处理。故还是找个公共的方式,axios官网提供了。

现在需要响应拦截器:
回到入口文件main.js:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import './plugins/element.js'
import qs from 'qs'
import axios from 'axios'
Vue.config.productionTip = false
/*为axios配置全局参数*/
//服务器路径
axios.defaults.baseURL="http://localhost:8080/"
//跨域带cookie
axios.defaults.withCredentials = true
//axios响应拦截器 配合后台登录访问控制
axios.interceptors.response.use(function (response) {
//如果没有登录 returnCode==20000
if(response.data.returnCode==20000){
//跳转到登录组件
router.push("/login");
}
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
Vue.prototype.$qs = qs;
Vue.prototype.$axios = axios
new Vue({
router,
render: h => h(App)
}).$mount('#app')
此时可删除其他组件发送请求失败时的else if。
至此,将系统里的公共功能写完了,每套系统以上部分都差不多。
接下来就写具体模块的增删改查。
vue工具下如何处理增删改查。
1.3菜单管理模块的增删改查

在menus组件加代码。
刚进该组件,应该先查现有的菜单信息。
1.3.1 查询功能
①.elementUI将表格拉过来:
菜单信息需要展示出来,故将table拉进来(之前讲过)。
(把代码复制一份)
<template>
<el-table
:data="tableData"
style="width: 100%">
<el-table-column
prop="date"
label="日期"
width="180">
</el-table-column>
<el-table-column
prop="name"
label="姓名"
width="180">
</el-table-column>
<el-table-column
prop="address"
label="地址">
</el-table-column>
</el-table>
</template>
<script>
export default {
data() {
return {
tableData: [{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1517 弄'
}, {
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1519 弄'
}, {
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1516 弄'
}]
}
}
}
</script>
<style>
</style>
②.绑定服务接口
要绑定的服务接口是MenuServlet(其配置地址是menu)
先发Ajax请求,并打印出返回的数据,看一下:
(参数可先不给,默认第一页,每页10条记录)
mounted(){
console.log("页面加载结束后执行");
this.$axios.get("/menu/query")
.then((ret)=>{
console.log(ret);
}).catch((err)=>{
console.log(err);
});
}
返回的数据如下:

所有的后台数据都有响应码,前端处理时根据响应码做一下区分。
若响应码是10000,做数据解析。
mounted(){
console.log("页面加载结束后执行");
this.$axios.get("/menu/query")
.then((ret)=>{
/*
从返回的数据复制一份
data:
pageinfo: {page: 1, pagesize: 10, total: 29}
returnCode: 10000
returnData: Array(10)
0: {glyphicon: 'el-icon-user', menuid: 11, menuname: '管理中心', menuurl: '#', pid: 0, …}
1: {glyphicon: 'el-icon-s-order', menuid: 12, menuname: '模版管理', menuurl: '#', pid: 0, …}
2: {glyphicon: 'el-icon-data-line', menuid: 13, menuname: '广告管理', menuurl: '#', pid: 0, …}
3: {glyphicon: 'el-icon-timer', menuid: 14, menuname: '游戏管理', menuurl: '#', pid: 0, …}
4: {glyphicon: 'el-icon-ship', menuid: 15, menuname: '合作公司管理', menuurl: '#', pid: 0, …}
5: {glyphicon: 'el-icon-setting', menuid: 16, menuname: '渠道版本', menuurl: '#', pid: 0, …}
6: {glyphicon: 'el-icon-setting', menuid: 17, menuname: 'CP', menuurl: '#', pid: 0, …}
7: {glyphicon: 'el-icon-setting', menuid: 18, menuname: '图书管理', menuurl: '#', pid: 0, …}
8: {glyphicon: 'el-icon-setting', menuid: 19, menuname: '标签管理', menuurl: '#', pid: 0, …}
9: {glyphicon: 'el-icon-setting', menuid: 20, menuname: '分类管理', menuurl: '#', pid: 0, …}
*/
console.log(ret);
if(ret.data.returnCode==10000){
this.tableData = ret.data.returnData;
}
}).catch((err)=>{
console.log(err);
});
}
假数据前面已经测试过,页面正常显示,先删除假数据:
data() {
return {
tableData: []
};
}
③.根据后台返回的字段修改el-table的数据:
会发现返回的数据多了个父级菜单的名字pname字段。数据库里只有pid,但前端最终展示给用户看,用父级菜单更合适。上级菜单的名称查询如下:
对应的sql:

把后台返回的字段在页面里修改一下:
<template>
<el-table
:data="tableData"
style="width: 100%">
<!--
glyphicon: "el-icon-user"
menuid: 11
menuname: "管理中心"
menuurl: "#"
pid: 0
pname: "无"
-->
<el-table-column
prop="menuid"
label="菜单编号">
</el-table-column>
<el-table-column
prop="menuname"
label="菜单名称">
</el-table-column>
<el-table-column
prop="menuurl"
label="访问地址">
</el-table-column>
<el-table-column
prop="pid"
label="上级菜单编号">
</el-table-column>
<el-table-column
prop="pname"
label="上级菜单名称">
</el-table-column>
<el-table-column
prop="glyphicon"
label="菜单图标">
</el-table-column>
</el-table>
</template>
效果如下:

图标直接来个文本不好看。
上面不是自己加的v-for,他是自动遍历的,故table里想自己加数据,需要用到数据插头。
显示一个图标,再显示一个文本:
<el-table-column
label="菜单图标">
<template v-slot="mydata">
<i :class="mydata.row.glyphicon"></i>
{{mydata.row.glyphicon}}
</template>
</el-table-column>
此时的代码:
<template>
<el-table
:data="tableData"
style="width: 100%">
<!--
glyphicon: "el-icon-user"
menuid: 11
menuname: "管理中心"
menuurl: "#"
pid: 0
pname: "无"
-->
<el-table-column
prop="menuid"
label="菜单编号">
</el-table-column>
<el-table-column
prop="menuname"
label="菜单名称">
</el-table-column>
<el-table-column
prop="menuurl"
label="访问地址">
</el-table-column>
<el-table-column
prop="pid"
label="上级菜单编号">
</el-table-column>
<el-table-column
prop="pname"
label="上级菜单名称">
</el-table-column>
<el-table-column
label="菜单图标">
<template v-slot="mydata">
<i :class="mydata.row.glyphicon"></i>
{{mydata.row.glyphicon}}
</template>
</el-table-column>
</el-table>
</template>
<script>
export default {
data() {
return {
tableData: []
};
},
mounted(){
console.log("页面加载结束后执行");
this.$axios.get("/menu/query")
.then((ret)=>{
/*
从返回的数据复制一份
data:
pageinfo: {page: 1, pagesize: 10, total: 29}
returnCode: 10000
returnData: Array(10)
0: {glyphicon: 'el-icon-user', menuid: 11, menuname: '管理中心', menuurl: '#', pid: 0, …}
1: {glyphicon: 'el-icon-s-order', menuid: 12, menuname: '模版管理', menuurl: '#', pid: 0, …}
2: {glyphicon: 'el-icon-data-line', menuid: 13, menuname: '广告管理', menuurl: '#', pid: 0, …}
3: {glyphicon: 'el-icon-timer', menuid: 14, menuname: '游戏管理', menuurl: '#', pid: 0, …}
4: {glyphicon: 'el-icon-ship', menuid: 15, menuname: '合作公司管理', menuurl: '#', pid: 0, …}
5: {glyphicon: 'el-icon-setting', menuid: 16, menuname: '渠道版本', menuurl: '#', pid: 0, …}
6: {glyphicon: 'el-icon-setting', menuid: 17, menuname: 'CP', menuurl: '#', pid: 0, …}
7: {glyphicon: 'el-icon-setting', menuid: 18, menuname: '图书管理', menuurl: '#', pid: 0, …}
8: {glyphicon: 'el-icon-setting', menuid: 19, menuname: '标签管理', menuurl: '#', pid: 0, …}
9: {glyphicon: 'el-icon-setting', menuid: 20, menuname: '分类管理', menuurl: '#', pid: 0, …}
*/
console.log(ret);
if(ret.data.returnCode==10000){
this.tableData = ret.data.returnData;
}
}).catch((err)=>{
console.log(err);
});
}
}
</script>
<style>
</style>
④.分页功能
从elementUI的Data找分页组件,复制一份过来,复制到el-table下面:
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="currentPage4" :page-sizes="[100, 200, 300, 400]" :page-size="100" layout="total, sizes, prev, pager, next, jumper" :total="400"> </el-pagination>
将:current-page="currentPage4"先改成:current-page="1"
函数handleSizeChange页码改变和handleCurrentChange每页显示多少条改变的对应函数也拉进来。
methods: {
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
},
handleCurrentChange(val) {
console.log(`当前页: ${val}`);
}
},
template标签里只能有一个分标签,故template里面最外层套一个div。
现在需要将分页组件和表格里的数据建立关系:
每次查询,后端发过来的数据都会有pageinfo

需要将pageinfo和分页组件的相关数据搭配起来:
先在data里建一个pageinfo对象,顺便做一组假数据:
data() {
return {
tableData: [],
/* pageinfo:
page: 1
pagesize: 10
total: 29 */
pageinfo:{
page: 3,
pagesize: 10,
total: 660
}
};
}
再将拉进来的分页插件做相应修改:
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="pageinfo.page" :page-sizes="[10, 20, 30]" :page-size="pageinfo.pagesize" layout="total, sizes, prev, pager, next, jumper" :total="pageinfo.total"> </el-pagination>
发Ajax请求时,页码相关数据传给分页插件:
(使用json对象的另一个好处,如果返回的键值对和设置的json对象的键值对完全一样,整个对象给他就行,不需要一个一个值去给)
if(ret.data.returnCode==10000){
//展示table数据
this.tableData = ret.data.returnData;
//把页码相关数据传给分页组件
//this.pageinfo = ret.data.pageinfo;
}
现在组件按真数据走,但翻页的功能还要改。翻页就是往后端传要看第几页,每页显示多少条。
handleCurrentChange(val) { //页数发生改变触发该函数
console.log(`当前页: ${val}`); //可知当前要翻的页数
}
只需再传查询的Ajax即可,上面最开始就是查询,多个查询可合并成一个。
故再新建个查询函数,其他的调用它:
methods: {
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
},
handleCurrentChange(val) { //页数发生改变触发该函数
console.log(`当前页: ${val}`); //可知当前要翻的页数
},
myQuery(params){
this.$axios.get("/menu/query?"+params) //get方式可直接拼参数
.then((ret)=>{
/*
从返回的数据复制一份
data:
pageinfo: {page: 1, pagesize: 10, total: 29}
returnCode: 10000
returnData: Array(10)
0: {glyphicon: 'el-icon-user', menuid: 11, menuname: '管理中心', menuurl: '#', pid: 0, …}
1: {glyphicon: 'el-icon-s-order', menuid: 12, menuname: '模版管理', menuurl: '#', pid: 0, …}
2: {glyphicon: 'el-icon-data-line', menuid: 13, menuname: '广告管理', menuurl: '#', pid: 0, …}
3: {glyphicon: 'el-icon-timer', menuid: 14, menuname: '游戏管理', menuurl: '#', pid: 0, …}
4: {glyphicon: 'el-icon-ship', menuid: 15, menuname: '合作公司管理', menuurl: '#', pid: 0, …}
5: {glyphicon: 'el-icon-setting', menuid: 16, menuname: '渠道版本', menuurl: '#', pid: 0, …}
6: {glyphicon: 'el-icon-setting', menuid: 17, menuname: 'CP', menuurl: '#', pid: 0, …}
7: {glyphicon: 'el-icon-setting', menuid: 18, menuname: '图书管理', menuurl: '#', pid: 0, …}
8: {glyphicon: 'el-icon-setting', menuid: 19, menuname: '标签管理', menuurl: '#', pid: 0, …}
9: {glyphicon: 'el-icon-setting', menuid: 20, menuname: '分类管理', menuurl: '#', pid: 0, …}
*/
console.log(ret);
if(ret.data.returnCode==10000){
//展示table数据
this.tableData = ret.data.returnData;
//把页码相关数据传给分页组件
this.pageinfo = ret.data.pageinfo;
}
}).catch((err)=>{
console.log(err);
});
}
},
mounted(){
console.log("页面加载结束后执行");
let params = ""
this.myQuery(params); //包含在vue对象里,直接调用即可。初次查询没有参数,给一个空值
}
现在处理翻页:
handleCurrentChange(val) { //页数发生改变触发该函数
console.log(`当前页: ${val}`); //可知当前要翻的页数
this.pageinfo.page = val; //将当前组件的page值设置成要翻页的页码
let params = this.$qs.stringify(this.pageinfo); //传一个pageinfo对象给后台,后端拿需要的参数即可
console.log(params); //先看一下这个参数
}
点击第二页,触发该函数,控制台输出:

参数没问题。
开始发参数:
handleCurrentChange(val) { //页数发生改变触发该函数
console.log(`当前页: ${val}`); //可知当前要翻的页数
this.pageinfo.page = val; //将当前组件的page值设置成要翻页的页码
let params = this.$qs.stringify(this.pageinfo); //传一个pageinfo对象给后台,后端拿需要的参数即可
console.log(params); //先看一下这个参数
this.myQuery(params); //要加this,不加this就找外部的全局参数。加this找vue里methods定义的函数。
}
现在翻页和跳页都正常了。
下拉列表里是页码数,点击20条/页,现在没反应,也需要传值查数据。
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
this.pageinfo.pagesize = val; //选中每页需要展示的页码数
this.pageinfo.page = 1; //切换pagesize之后,习惯将页数指定到第一页
let params = this.$qs.stringify(this.pageinfo);
console.log(params);
this.myQuery(params);
}
至此,翻页功能做完。
现在全部的代码:
<template>
<div>
<el-table
:data="tableData"
style="width: 100%">
<!--
glyphicon: "el-icon-user"
menuid: 11
menuname: "管理中心"
menuurl: "#"
pid: 0
pname: "无"
-->
<el-table-column
prop="menuid"
label="菜单编号">
</el-table-column>
<el-table-column
prop="menuname"
label="菜单名称">
</el-table-column>
<el-table-column
prop="menuurl"
label="访问地址">
</el-table-column>
<el-table-column
prop="pid"
label="上级菜单编号">
</el-table-column>
<el-table-column
prop="pname"
label="上级菜单名称">
</el-table-column>
<el-table-column
label="菜单图标">
<template v-slot="mydata">
<i :class="mydata.row.glyphicon"></i>
{{mydata.row.glyphicon}}
</template>
</el-table-column>
</el-table>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageinfo.page"
:page-sizes="[10, 20, 30]"
:page-size="pageinfo.pagesize"
layout="total, sizes, prev, pager, next, jumper"
:total="pageinfo.total">
</el-pagination>
</div>
</template>
<script>
export default {
data() {
return {
tableData: [],
/* pageinfo:
page: 1
pagesize: 10
total: 29 */
pageinfo:{
page: 3,
pagesize: 10,
total: 660
}
};
},
methods: {
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
this.pageinfo.pagesize = val; //选中每页需要展示的页码数
this.pageinfo.page = 1; //切换pagesize之后,习惯将页数指定到第一页
let params = this.$qs.stringify(this.pageinfo);
console.log(params);
this.myQuery(params);
},
handleCurrentChange(val) { //页数发生改变触发该函数
console.log(`当前页: ${val}`); //可知当前要翻的页数
this.pageinfo.page = val; //将当前组件的page值设置成要翻页的页码
let params = this.$qs.stringify(this.pageinfo); //传一个pageinfo对象给后台,后端拿需要的参数即可
console.log(params); //先看一下这个参数
this.myQuery(params); //要加this,不加this就找外部的全局参数。
},
myQuery(params){
this.$axios.get("/menu/query?"+params)
.then((ret)=>{
console.log(ret);
if(ret.data.returnCode==10000){
//展示table数据
this.tableData = ret.data.returnData;
//把页码相关数据传给分页组件
this.pageinfo = ret.data.pageinfo;
}
}).catch((err)=>{
console.log(err);
});
}
},
mounted(){
console.log("页面加载结束后执行");
let params = "";
this.myQuery(params);
}
}
</script>
<style>
</style>
页面效果:

⑤.条件查询
后端MenuServlet条件查询需要接收的参数是qmname和qpid。故前端应该把这两个值传到后台。
name部分模糊查询,id部分精确查询。
到elementUI拉一个查询按钮和两个框。在Form表单部分。
复制的内容放到el-table上面:
<el-form :inline="true" :model="formInline" class="demo-form-inline"> <el-form-item label="审批人"> <el-input v-model="formInline.user" placeholder="审批人"></el-input> </el-form-item> <el-form-item label="活动区域"> <el-select v-model="formInline.region" placeholder="活动区域"> <el-option label="区域一" value="shanghai"></el-option> <el-option label="区域二" value="beijing"></el-option> </el-select> </el-form-item> <el-form-item> <el-button type="primary" @click="onSubmit">查询</el-button> </el-form-item> </el-form>
修改内容:
绑定queryForm对象,queryForm传的两个值和后台搭配起来。
<el-form :inline="true" :model="queryForm" class="demo-form-inline">
<el-form-item label="菜单名称">
<el-input v-model="queryForm.qmname" placeholder="menuname"></el-input>
</el-form-item>
<el-form-item label="父菜单">
<el-input v-model="queryForm.qpid" placeholder="pid"></el-input>
</el-form-item>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="queryMenu()">查询</el-button>
</el-form-item>
</el-form>
将对象创建出来:
queryForm:{
qmname:'', //做双向绑定时,就不给假数据了,默认空值
qpid:''
}
将查询函数写出来:
queryMenu(){
let params = this.$qs.stringify(this.queryForm);
this.myQuery(params);
}
测试:
模糊查询:

再翻翻页(翻页也带条件)
翻页的时候,参数多添加一些:
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
this.pageinfo.pagesize = val; //选中每页需要展示的页码数
this.pageinfo.page = 1; //切换pagesize之后,习惯将页数指定到第一页
let params = this.$qs.stringify(this.pageinfo)+"&"+this.$qs.stringify(this.queryForm);
console.log(params);
this.myQuery(params);
},
handleCurrentChange(val) { //页数发生改变触发该函数
console.log(`当前页: ${val}`); //可知当前要翻的页数
this.pageinfo.page = val; //将当前组件的page值设置成要翻页的页码
let params = this.$qs.stringify(this.pageinfo)+"&"+this.$qs.stringify(this.queryForm); ; //传一个 pageinfo对象给后台,后端拿需要的参数即可
console.log(params); //先看一下这个参数
this.myQuery(params); //要加this,不加this就找外部的全局参数。
}
再测,翻页时也带上了条件。
精确查询:

再测个父菜单0的,并且翻翻页。
再测菜单名称:管理234,父菜单:0。找个没数据的。
⑥.查询改成下拉列表
两个输入框使用不方便。将数据库里父id有的数据放在父菜单做成下拉列表。
还是刚才Form表单的那个例子,将相关代码复制进来:
<el-form :inline="true" :model="queryForm" class="demo-form-inline">
<el-form-item label="菜单名称">
<el-input v-model="queryForm.qmname" placeholder="menuname"></el-input>
</el-form-item>
<el-form-item label="父菜单">
<el-select v-model="queryForm.qpid" placeholder="pid">
<el-option label="无" value="0"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="queryMenu()">查询</el-button>
</el-form-item>
</el-form>
效果如下:

无是特殊的一个。不需要从后台拿。
下拉列表的相关数据从后台获取:

对应的在MenuServlet里有getmenuselect方法。
在postman里测一下:

将菜单数据的方法定义下:
将拿到的数据传给selectOptions
getMenuSelect(){
this.$axios.get("/menu/getmenuselect")
.then((ret)=>{
console.log(ret);
if(ret.data.returnCode==10000){
//展示table数据
this.selectOptions = ret.data.returnData;
}
}).catch((err)=>{
console.log(err);
});
}
}
相应的data里增加:
selectOptions:[],
回到下拉列表,需要增加的选项用v-for从selectOptions里遍历拿数据。
label里写名称(给用户看),value里写值(往后台做查询用)。
<el-form :inline="true" :model="queryForm" class="demo-form-inline">
<el-form-item label="菜单名称">
<el-input v-model="queryForm.qmname" placeholder="menuname"></el-input>
</el-form-item>
<el-form-item label="父菜单">
<el-select v-model="queryForm.qpid" placeholder="pid">
<el-option label="无" value="0"></el-option>
<el-option v-for="opt in selectOptions" :label="opt.menuname" :value="opt.menuid"></el-option>
</el-select>
</el-form-item>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="queryMenu()">查询</el-button>
</el-form-item>
</el-form>
页面加载结束后,拿下拉列表的数据:
mounted(){
console.log("页面加载结束后执行");
let params = "";
this.myQuery(params);
this.getMenuSelect();
}
⑦.重置查询表单
增加一个重置按钮,清空el-form表单数据。
首先给el-form加ref属性,将组件注册上去。
然后加一个点击事件,将注册后的名字以参数形式传入。
<el-form ref="queryForm" :inline="true" :model="queryForm" class="demo-form-inline">
<el-form-item label="菜单名称">
<el-input v-model="queryForm.qmname" placeholder="menuname"></el-input>
</el-form-item>
<el-form-item label="父菜单">
<el-select v-model="queryForm.qpid" placeholder="pid">
<el-option label="无" value="0"></el-option>
<el-option v-for="opt in selectOptions" :label="opt.menuname" :value="opt.menuid"></el-option>
</el-select>
</el-form-item>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="queryMenu()">查询</el-button>
<el-button type="info" plain @click="resetForm('queryForm')">重置</el-button>
</el-form-item>
</el-form>
增加重置函数:
resetForm(formname){
this.$refs[formname].resetFields();
}
form-item上需要有prop属性:
<el-form ref="queryForm" :inline="true" :model="queryForm" class="demo-form-inline">
<el-form-item label="菜单名称" prop="qmname">
<el-input v-model="queryForm.qmname" placeholder="menuname"></el-input>
</el-form-item>
<el-form-item label="父菜单" prop="qpid">
<el-select v-model="queryForm.qpid" placeholder="pid">
<el-option label="无" value="0"></el-option>
<el-option v-for="opt in selectOptions" :label="opt.menuname" :value="opt.menuid"></el-option>
</el-select>
</el-form-item>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="queryMenu()">查询</el-button>
<el-button type="info" plain @click="resetForm('queryForm')">重置</el-button>
</el-form-item>
</el-form>
查询功能结束,代码如下:
<template>
<div>
<el-form ref="queryForm" :inline="true" :model="queryForm" class="demo-form-inline">
<el-form-item label="菜单名称" prop="qmname">
<el-input v-model="queryForm.qmname" placeholder="menuname"></el-input>
</el-form-item>
<el-form-item label="父菜单" prop="qpid">
<el-select v-model="queryForm.qpid" placeholder="pid">
<el-option label="无" value="0"></el-option>
<el-option v-for="opt in selectOptions" :label="opt.menuname" :value="opt.menuid"></el-option>
</el-select>
</el-form-item>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="queryMenu()">查询</el-button>
<el-button type="info" plain @click="resetForm('queryForm')">重置</el-button>
</el-form-item>
</el-form>
<el-table
:data="tableData"
style="width: 100%">
<!--
glyphicon: "el-icon-user"
menuid: 11
menuname: "管理中心"
menuurl: "#"
pid: 0
pname: "无"
-->
<el-table-column
prop="menuid"
label="菜单编号">
</el-table-column>
<el-table-column
prop="menuname"
label="菜单名称">
</el-table-column>
<el-table-column
prop="menuurl"
label="访问地址">
</el-table-column>
<el-table-column
prop="pid"
label="上级菜单编号">
</el-table-column>
<el-table-column
prop="pname"
label="上级菜单名称">
</el-table-column>
<el-table-column
label="菜单图标">
<template v-slot="mydata">
<i :class="mydata.row.glyphicon"></i>
{{mydata.row.glyphicon}}
</template>
</el-table-column>
</el-table>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageinfo.page"
:page-sizes="[10, 20, 30]"
:page-size="pageinfo.pagesize"
layout="total, sizes, prev, pager, next, jumper"
:total="pageinfo.total">
</el-pagination>
</div>
</template>
<script>
export default {
data() {
return {
tableData: [],
selectOptions:[],
/* pageinfo:
page: 1
pagesize: 10
total: 29 */
pageinfo:{
page: 3,
pagesize: 10,
total: 660
},
queryForm:{
qmname:'', //做双向绑定时,就不给假数据了,默认空值
qpid:''
}
};
},
methods: {
resetForm(formname){
this.$refs[formname].resetFields();
},
queryMenu(){
let params = this.$qs.stringify(this.queryForm);
this.myQuery(params);
},
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
this.pageinfo.pagesize = val; //选中每页需要展示的页码数
this.pageinfo.page = 1; //切换pagesize之后,习惯将页数指定到第一页
let params = this.$qs.stringify(this.pageinfo)+"&"+this.$qs.stringify(this.queryForm);
console.log(params);
this.myQuery(params);
},
handleCurrentChange(val) { //页数发生改变触发该函数
console.log(`当前页: ${val}`); //可知当前要翻的页数
this.pageinfo.page = val; //将当前组件的page值设置成要翻页的页码
let params = this.$qs.stringify(this.pageinfo)+"&"+this.$qs.stringify(this.queryForm); ; //传一个pageinfo对象给后台,后端拿需要的参数即可
console.log(params); //先看一下这个参数
this.myQuery(params); //要加this,不加this就找外部的全局参数。
},
myQuery(params){
this.$axios.get("/menu/query?"+params)
.then((ret)=>{
console.log(ret);
if(ret.data.returnCode==10000){
//展示table数据
this.tableData = ret.data.returnData;
//把页码相关数据传给分页组件
this.pageinfo = ret.data.pageinfo;
}
}).catch((err)=>{
console.log(err);
});
},
getMenuSelect(){
this.$axios.get("/menu/getmenuselect")
.then((ret)=>{
console.log(ret);
if(ret.data.returnCode==10000){
//展示table数据
this.selectOptions = ret.data.returnData;
}
}).catch((err)=>{
console.log(err);
});
}
},
mounted(){
console.log("页面加载结束后执行");
let params = "";
this.myQuery(params);
this.getMenuSelect();
}
}
</script>
<style>
</style>
效果如下:

1.3.2添加功能
增加添加按钮,添加信息时弹出弹出框。
①.elementUI拉过弹出框
在Others的Dialog,复制相关代码:
放到div里的最下层:
<el-button type="text" @click="dialogFormVisible = true">打开嵌套表单的 Dialog</el-button>
<el-dialog title="收货地址" :visible.sync="dialogFormVisible">
<el-form :model="form">
<el-form-item label="活动名称" :label-width="formLabelWidth">
<el-input v-model="form.name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="活动区域" :label-width="formLabelWidth">
<el-select v-model="form.region" placeholder="请选择活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="dialogFormVisible = false">确 定</el-button>
</div>
</el-dialog>
按钮还是放上面:
换一下添加按钮的样式
<el-button type="primary" @click="queryMenu()">查询</el-button>
<el-button type="info" plain @click="resetForm('queryForm')">重置</el-button>
<el-button type="success" @click="dialogFormVisible = true">打开嵌套表单的 Dialog</el-button>
关键的值在data里定义一下:
dialogFormVisible : false, formLabelWidth: '120px'
新拉进来的代码还绑定了form,故在data里,定义绑定的数据:(改成addForm)
addForm:{
myval1:'',
myval2:''
}
上面的数据将form也全部改成addForm,并修改相应参数:
<el-dialog title="收货地址" :visible.sync="dialogFormVisible">
<el-form :model="addForm">
<el-form-item label="活动名称" :label-width="formLabelWidth">
<el-input v-model="addForm.myval1" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="活动区域" :label-width="formLabelWidth">
<el-select v-model="addForm.myval2" placeholder="请选择活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="dialogFormVisible = false">确 定</el-button>
</div>
</el-dialog>
dialogFormVisible太长,以上全部换成addFormVisible
将添加按钮的内容改成添加
<el-button type="success" @click="dialogFormVisible = true">添加</el-button>
设置弹出框的内容:
父id应该做成下拉列表。
<!-- String menuid = req.getParameter("menuid");
String menuname = req.getParameter("menuname");
String menuurl = req.getParameter("menuurl");
String pid = req.getParameter("pid");
String glyphicon = req.getParameter("glyphicon"); -->
<el-dialog title="添加" :visible.sync="addFormVisible">
<el-form :model="addForm">
<el-form-item label="菜单编号" :label-width="formLabelWidth">
<el-input v-model="addForm.menuid" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="菜单名称" :label-width="formLabelWidth">
<el-input v-model="addForm.menuname" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="访问地址" :label-width="formLabelWidth">
<el-input v-model="addForm.menuurl" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="父菜单" prop="qpid">
<el-select v-model="addForm.pid" placeholder="pid">
<el-option label="无" value="0"></el-option>
<el-option v-for="opt in selectOptions" :label="opt.menuname" :value="opt.menuid"></el-option>
</el-select>
</el-form-item>
<el-form-item label="图标" :label-width="formLabelWidth">
<el-input v-model="addForm.glyphicon" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="addFormVisible = false">取 消</el-button>
<el-button type="primary" @click="addFormVisible = false">确 定</el-button>
</div>
</el-dialog>
将假数据改成真数据:
/* String menuid = req.getParameter("menuid");
String menuname = req.getParameter("menuname");
String menuurl = req.getParameter("menuurl");
String pid = req.getParameter("pid");
String glyphicon = req.getParameter("glyphicon"); */
addForm:{
menuid:'',
menuname:'',
menuurl:'',
pid:'',
glyphicon:'',
}
效果如下:

修改父菜单样式:
<el-form-item label="父菜单" prop="qpid" :label-width="formLabelWidth">
同时在样式标签里:
.el-select{
width:100%;
}
点击确定后,应往后台发送,也做成一个函数:
<el-button type="primary" @click="addFormSubmit()">确 定</el-button>
对应函数:
addFormSubmit(){
this.addFormVisible = false; //让弹出框关闭
//this.$qs.stringify(this.addForm); //取addForm数据,并格式化
this.$axios.post("/menu/add",this.$qs.stringify(this.addForm))
.then((ret)=>{ //先和接口接通
}).catch((err)=>{
})
}
随便写一组数据,点击确定,数据库添加成功。
②.做出弹出框后,添加数据结束,使页面相应改变
添加请求成功,但页面没反应。故干两个事:
1.数据刷新(实际是重新查询一遍) 2.打印出执行操作的结果(用提示框)。
接收到后台的响应代码后,做出不同的提示框(代码从elementUI取)。
this.$axios.post("/menu/add",this.$qs.stringify(this.addForm))
.then((ret)=>{ //先和接口接通
//根据响应 提示操作的结果
if(ret.data.returnCode==10000){
this.$message(ret.data.returnMsg);
}else{
this.$message.error(ret.data.returnMsg);
}
}).catch((err)=>{
})
刷新数据:
this.$axios.post("/menu/add",this.$qs.stringify(this.addForm))
.then((ret)=>{ //先和接口接通
//根据响应 提示操作的结果
if(ret.data.returnCode==10000){
this.$message({
message:ret.data.returnMsg,
type: 'success'
});
}else{
this.$message.error(ret.data.returnMsg);
}
//刷新数据
let params = this.$qs.stringify(this.pageinfo)+"&"+this.$qs.stringify(this.queryForm);
this.myQuery(params);
}).catch((err)=>{
})
③.一个问题:添加完成以后,父菜单的下拉列表没有跟着动。

因为该下拉列表是页面加载结束取的。添加完数据没有再取数据。故刷新数据也要刷新父菜单的下拉列表数据:
this.$axios.post("/menu/add",this.$qs.stringify(this.addForm))
.then((ret)=>{ //先和接口接通
//根据响应 提示操作的结果
if(ret.data.returnCode==10000){
this.$message({
message:ret.data.returnMsg,
type: 'success'
});
}else{
this.$message.error(ret.data.returnMsg);
}
//刷新数据
let params = this.$qs.stringify(this.pageinfo)+"&"+this.$qs.stringify(this.queryForm);
this.myQuery(params);
//刷新下拉列表数据:
this.getMenuSelect();
}).catch((err)=>{
})
添加结束后,再添加数据时,上一次的数据还在。应该再次点击添加按钮时,弹出框的数据清空。
找到添加按钮:
<el-button type="success" @click="addFormOpen('addForm')">添加</el-button>
找到表格,注册一下addForm,并给下面的表格项增加prop属性:
<el-dialog title="添加" :visible.sync="addFormVisible">
<el-form ref="addForm" :model="addForm">
<el-form-item label="菜单编号" :label-width="formLabelWidth" prop="menuid">
<el-input v-model="addForm.menuid" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="菜单名称" :label-width="formLabelWidth" prop="menuname">
<el-input v-model="addForm.menuname" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="访问地址" :label-width="formLabelWidth" prop="menuurl">
<el-input v-model="addForm.menuurl" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="父菜单" prop="qpid" :label-width="formLabelWidth">
<el-select v-model="addForm.pid" placeholder="pid">
<el-option label="无" value="0"></el-option>
<el-option v-for="opt in selectOptions" :label="opt.menuname" :value="opt.menuid"></el-option>
</el-select>
</el-form-item>
<el-form-item label="图标" :label-width="formLabelWidth" prop="glyphicon">
<el-input v-model="addForm.glyphicon" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="addFormVisible = false">取 消</el-button>
<el-button type="primary" @click="addFormSubmit()">确 定</el-button>
</div>
</el-dialog>
在下面定义该函数:
addFormOpen(formName){
this.addFormVisible = true;
this.$refs[formName].resetFields();
}
④.功能正常,但还报错
虽然可以正常运行,但这里报错

意思是this.$refs[formName]是空的,再拿空对象调resetFields()。类似java里的空指针异常。
组件已经注册上去,怎么会空?
这是vue机制问题,它的渲染过程是自动的,交给它的代码的执行顺序不一定是我们编写的代码的顺序。
使用这个对象时,组件还没注册,故报错。
解决办法:
addFormOpen(formName){
this.addFormVisible = true;
this.$nextTick(function(){ //渲染时机后移,做完一次渲染后再执行括号里的代码
this.$refs[formName].resetFields();
})
}
增加功能结束,代码如下:
<template>
<div>
<el-form ref="queryForm" :inline="true" :model="queryForm" class="demo-form-inline">
<el-form-item label="菜单名称" prop="qmname">
<el-input v-model="queryForm.qmname" placeholder="menuname"></el-input>
</el-form-item>
<el-form-item label="父菜单" prop="qpid">
<el-select v-model="queryForm.qpid" placeholder="pid">
<el-option label="无" value="0"></el-option>
<el-option v-for="opt in selectOptions" :label="opt.menuname" :value="opt.menuid"></el-option>
</el-select>
</el-form-item>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="queryMenu()">查询</el-button>
<el-button type="info" plain @click="resetForm('queryForm')">重置</el-button>
<el-button type="success" @click="addFormOpen('addForm')">添加</el-button>
</el-form-item>
</el-form>
<el-table
:data="tableData"
style="width: 100%">
<!--
glyphicon: "el-icon-user"
menuid: 11
menuname: "管理中心"
menuurl: "#"
pid: 0
pname: "无"
-->
<el-table-column
prop="menuid"
label="菜单编号">
</el-table-column>
<el-table-column
prop="menuname"
label="菜单名称">
</el-table-column>
<el-table-column
prop="menuurl"
label="访问地址">
</el-table-column>
<el-table-column
prop="pid"
label="上级菜单编号">
</el-table-column>
<el-table-column
prop="pname"
label="上级菜单名称">
</el-table-column>
<el-table-column
label="菜单图标">
<template v-slot="mydata">
<i :class="mydata.row.glyphicon"></i>
{{mydata.row.glyphicon}}
</template>
</el-table-column>
</el-table>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageinfo.page"
:page-sizes="[10, 20, 30]"
:page-size="pageinfo.pagesize"
layout="total, sizes, prev, pager, next, jumper"
:total="pageinfo.total">
</el-pagination>
<!-- String menuid = req.getParameter("menuid");
String menuname = req.getParameter("menuname");
String menuurl = req.getParameter("menuurl");
String pid = req.getParameter("pid");
String glyphicon = req.getParameter("glyphicon"); -->
<el-dialog title="添加" :visible.sync="addFormVisible">
<el-form ref="addForm" :model="addForm">
<el-form-item label="菜单编号" :label-width="formLabelWidth" prop="menuid">
<el-input v-model="addForm.menuid" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="菜单名称" :label-width="formLabelWidth" prop="menuname">
<el-input v-model="addForm.menuname" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="访问地址" :label-width="formLabelWidth" prop="menuurl">
<el-input v-model="addForm.menuurl" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="父菜单" prop="qpid" :label-width="formLabelWidth">
<el-select v-model="addForm.pid" placeholder="pid">
<el-option label="无" value="0"></el-option>
<el-option v-for="opt in selectOptions" :label="opt.menuname" :value="opt.menuid"></el-option>
</el-select>
</el-form-item>
<el-form-item label="图标" :label-width="formLabelWidth" prop="glyphicon">
<el-input v-model="addForm.glyphicon" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="addFormVisible = false">取 消</el-button>
<el-button type="primary" @click="addFormSubmit()">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
data() {
return {
tableData: [],
selectOptions:[],
/* pageinfo:
page: 1
pagesize: 10
total: 29 */
pageinfo:{
page: 3,
pagesize: 10,
total: 660
},
queryForm:{
qmname:'', //做双向绑定时,就不给假数据了,默认空值
qpid:''
},
/* String menuid = req.getParameter("menuid");
String menuname = req.getParameter("menuname");
String menuurl = req.getParameter("menuurl");
String pid = req.getParameter("pid");
String glyphicon = req.getParameter("glyphicon"); */
addForm:{
menuid:'',
menuname:'',
menuurl:'',
pid:'',
glyphicon:'',
},
addFormVisible : false,
formLabelWidth: '120px'
};
},
methods: {
addFormOpen(formName){
this.addFormVisible = true;
this.$nextTick(function(){ //渲染时机后移,做完一次渲染后再执行括号里的代码
this.$refs[formName].resetFields();
})
},
addFormSubmit(){
this.addFormVisible = false; //让弹出框关闭
//this.$qs.stringify(this.addForm); //取addForm数据,并格式化
this.$axios.post("/menu/add",this.$qs.stringify(this.addForm))
.then((ret)=>{ //先和接口接通
//根据响应 提示操作的结果
if(ret.data.returnCode==10000){
this.$message({
message:ret.data.returnMsg,
type: 'success'
});
}else{
this.$message.error(ret.data.returnMsg);
}
//刷新数据
let params = this.$qs.stringify(this.pageinfo)+"&"+this.$qs.stringify(this.queryForm);
this.myQuery(params);
//刷新下拉列表数据:
this.getMenuSelect();
}).catch((err)=>{
})
},
resetForm(formname){
this.$refs[formname].resetFields();
},
queryMenu(){
let params = this.$qs.stringify(this.queryForm);
this.myQuery(params);
},
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
this.pageinfo.pagesize = val; //选中每页需要展示的页码数
this.pageinfo.page = 1; //切换pagesize之后,习惯将页数指定到第一页
let params = this.$qs.stringify(this.pageinfo)+"&"+this.$qs.stringify(this.queryForm);
console.log(params);
this.myQuery(params);
},
handleCurrentChange(val) { //页数发生改变触发该函数
console.log(`当前页: ${val}`); //可知当前要翻的页数
this.pageinfo.page = val; //将当前组件的page值设置成要翻页的页码
let params = this.$qs.stringify(this.pageinfo)+"&"+this.$qs.stringify(this.queryForm); //传一个pageinfo对象给后台,后端拿需要的参数即可
console.log(params); //先看一下这个参数
this.myQuery(params); //要加this,不加this就找外部的全局参数。
},
myQuery(params){
this.$axios.get("/menu/query?"+params)
.then((ret)=>{
console.log(ret);
if(ret.data.returnCode==10000){
//展示table数据
this.tableData = ret.data.returnData;
//把页码相关数据传给分页组件
this.pageinfo = ret.data.pageinfo;
}
}).catch((err)=>{
console.log(err);
});
},
getMenuSelect(){
this.$axios.get("/menu/getmenuselect")
.then((ret)=>{
console.log(ret);
if(ret.data.returnCode==10000){
//展示table数据
this.selectOptions = ret.data.returnData;
}
}).catch((err)=>{
console.log(err);
});
}
},
mounted(){
console.log("页面加载结束后执行");
let params = "";
this.myQuery(params);
this.getMenuSelect();
}
}
</script>
<style>
.el-select{
width:100%;
}
</style>
1.3.3修改功能
①.定位当前行数据
法一:每一行记录加一个修改按钮
法二:使table变成可选择的效果
这里用法二,elementUI的Table表格,复制相关代码(单选):
Table 组件提供了单选的支持,只需要配置highlight-current-row属性即可实现单选。之后由current-change事件来管理选中时触发的事件,它会传入currentRow,oldCurrentRow。如果需要显示索引,可以增加一列el-table-column,设置type属性为index即可显示从 1 开始的索引号。
在页面显示的table标签上:
<el-table :data="tableData" highlight-current-row @current-change="handleCurrentChange()" style="width: 100%">
定义该方法:
该方法名被翻页占了,改成selectRowChange
selectRowChange(val){ //参数是当前改变的这行数据
this.currentRow = val;
}
data里定义该对象:
currentRow: null
按钮那块没传参,改成如下,就是用它的默认参数:
@current-change="handleCurrentChange"
现在行就选中了。再加一个按钮:
<el-button type="warning" @click="editFormOpen('editForm')">修改</el-button>
②.将选中行数据填到修改框里
editForm和添加很像。
直接复制一份addForm,做修改即可。
菜单编号不让修改,只读。
<el-dialog title="修改" :visible.sync="editFormVisible">
<el-form ref="editForm" :model="editForm">
<el-form-item label="菜单编号" :label-width="formLabelWidth" prop="menuid">
<el-input v-model="editForm.menuid" autocomplete="off" readonly></el-input>
</el-form-item>
<el-form-item label="菜单名称" :label-width="formLabelWidth" prop="menuname">
<el-input v-model="editForm.menuname" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="访问地址" :label-width="formLabelWidth" prop="menuurl">
<el-input v-model="editForm.menuurl" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="父菜单" prop="qpid" :label-width="formLabelWidth">
<el-select v-model="editForm.pid" placeholder="pid">
<el-option label="无" value="0"></el-option>
<el-option v-for="opt in selectOptions" :label="opt.menuname" :value="opt.menuid"></el-option>
</el-select>
</el-form-item>
<el-form-item label="图标" :label-width="formLabelWidth" prop="glyphicon">
<el-input v-model="editForm.glyphicon" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="editFormVisible = false">取 消</el-button>
<el-button type="primary" @click="editFormSubmit()">确 定</el-button>
</div>
</el-dialog>
下面对应的数据:
将data里addForm复制一份修改:
editForm:{
menuid:'',
menuname:'',
menuurl:'',
pid:'',
glyphicon:'',
},
editFormVisible : false,
点击修改按钮,先让它的弹出框出来:
editFormOpen(){
this.editFormVisible = true;
}
接下来将选中的数据填到弹出框:

即将选中的数据填到editForm字段里:
editFormOpen(){
this.editFormVisible = true;
this.editForm = this.currentRow; //将选中行的数据对象填到editForm里
}
选中不同的行,修改框里的父菜单内容有点问题:
这是数据类型的问题:

select里,0是自己拼的。其他的值是动态生成的。
使用value数据绑定时,后台给的格式和这个格式对应,现在使用menuid实际是数字类型。这个选项和它的类型没有匹配上。
这里加个冒号,变成数值绑定,里面写的js代码,0就是数字0.(第一天讲value时的问题)
<el-select v-model="editForm.pid" placeholder="pid">
<el-option label="无" :value="0"></el-option>
<el-option v-for="opt in selectOptions" :label="opt.menuname" :value="opt.menuid"></el-option>
</el-select>
③.修改数据

修改数据,还没传到后台,页面数据就改变了。
这也是vue里的一个机制,vue会把这些对象监控起来

里面有一个ob,即Observer。表示对象被监控了,并且每个对象会起一个对应的对象编号。这个对象是遍历数据时生成的。
editFormOpen(){
this.editFormVisible = true;
//将选中行的数据对象填到editForm里
//this.editForm = this.currentRow; //这里实际只传了对象的引用,故editForm里的数据修改,页面数据也会改。他们指向同一个引用,并且做了数据双向绑定
//java里也有同样的问题,深克隆和浅克隆
//console.log(JSON.stringify(this.currentRow)); //json格式字符串化,且是标准的json格式
//console.log(JSON.parse(JSON.stringify(this.currentRow))); //将对象转成字符串,再转回来,就新创建了一个对象,虽然数据还是一样的
//this.editForm = this.currentRow; //用新的对象赋值给editForm。这就是js里的深克隆
this.editForm = JSON.parse(JSON.stringify(this.currentRow)); //可写成一句话
}
接下来点击修改弹出框的确定按钮,将数据从editFrom里拿到,传给后台,后台保存起来。
editFormSubmit函数类似addFormSubmit:
editFormSubmit(){
this.editFormVisible = false; //让弹出框关闭
this.$axios.post("/menu/edit",this.$qs.stringify(this.editForm))
.then((ret)=>{
if(ret.data.returnCode==10000){
this.$message({
message:ret.data.returnMsg,
type: 'success'
});
}else{
this.$message.error(ret.data.returnMsg);
}
//刷新数据
let params = this.$qs.stringify(this.pageinfo)+"&"+this.$qs.stringify(this.queryForm);
this.myQuery(params);
//刷新下拉列表数据:
this.getMenuSelect();
}).catch((err)=>{
})
}
除了参数不同,都一致。
再加一个函数,写公共代码:
myCUD(url,params){
this.$axios.post(url,params)
.then((ret)=>{ //先和接口接通
//根据响应 提示操作的结果
if(ret.data.returnCode==10000){
this.$message({
message:ret.data.returnMsg,
type: 'success'
});
}else{
this.$message.error(ret.data.returnMsg);
}
//刷新数据
let params = this.$qs.stringify(this.pageinfo)+"&"+this.$qs.stringify(this.queryForm);
this.myQuery(params);
//刷新下拉列表数据:
this.getMenuSelect();
}).catch((err)=>{
})
}
修改:
editFormSubmit(){
this.editFormVisible = false; //让弹出框关闭
let url = "/menu/edit";
let params = this.$qs.stringify(this.editForm);
this.myCUD(url,params);
}
添加:
addFormSubmit(){
this.addFormVisible = false; //让弹出框关闭
let url = "/menu/add";
let params = this.$qs.stringify(this.addForm);
this.myCUD(url,params);
}
此时,整体代码如下:
<template>
<div>
<el-form ref="queryForm" :inline="true" :model="queryForm" class="demo-form-inline">
<el-form-item label="菜单名称" prop="qmname">
<el-input v-model="queryForm.qmname" placeholder="menuname"></el-input>
</el-form-item>
<el-form-item label="父菜单" prop="qpid">
<el-select v-model="queryForm.qpid" placeholder="pid">
<el-option label="无" value="0"></el-option>
<el-option v-for="opt in selectOptions" :label="opt.menuname" :value="opt.menuid"></el-option>
</el-select>
</el-form-item>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="queryMenu()">查询</el-button>
<el-button type="info" plain @click="resetForm('queryForm')">重置</el-button>
<el-button type="success" @click="addFormOpen('addForm')">添加</el-button>
<el-button type="warning" @click="editFormOpen('editForm')">修改</el-button>
</el-form-item>
</el-form>
<el-table
:data="tableData"
highlight-current-row
@current-change="selectRowChange"
style="width: 100%">
<el-table-column
prop="menuid"
label="菜单编号">
</el-table-column>
<el-table-column
prop="menuname"
label="菜单名称">
</el-table-column>
<el-table-column
prop="menuurl"
label="访问地址">
</el-table-column>
<el-table-column
prop="pid"
label="上级菜单编号">
</el-table-column>
<el-table-column
prop="pname"
label="上级菜单名称">
</el-table-column>
<el-table-column label="菜单图标">
<template v-slot="mydata">
<i :class="mydata.row.glyphicon"></i>{{mydata.row.glyphicon}}
</template>
</el-table-column>
</el-table>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageinfo.page"
:page-sizes="[10, 20, 30]"
:page-size="pageinfo.pagesize"
layout="total, sizes, prev, pager, next, jumper"
:total="pageinfo.total">
</el-pagination>
<!-- String menuid = req.getParameter("menuid");
String menuname = req.getParameter("menuname");
String menuurl = req.getParameter("menuurl");
String pid = req.getParameter("pid");
String glyphicon = req.getParameter("glyphicon"); -->
<el-dialog title="添加" :visible.sync="addFormVisible">
<el-form ref="addForm" :model="addForm">
<el-form-item label="菜单编号" :label-width="formLabelWidth" prop="menuid">
<el-input v-model="addForm.menuid" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="菜单名称" :label-width="formLabelWidth" prop="menuname">
<el-input v-model="addForm.menuname" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="访问地址" :label-width="formLabelWidth" prop="menuurl">
<el-input v-model="addForm.menuurl" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="父菜单" prop="qpid" :label-width="formLabelWidth">
<el-select v-model="addForm.pid" placeholder="pid">
<el-option label="无" value="0"></el-option>
<el-option v-for="opt in selectOptions" :label="opt.menuname" :value="opt.menuid"></el-option>
</el-select>
</el-form-item>
<el-form-item label="图标" :label-width="formLabelWidth" prop="glyphicon">
<el-input v-model="addForm.glyphicon" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="addFormVisible = false">取 消</el-button>
<el-button type="primary" @click="addFormSubmit()">确 定</el-button>
</div>
</el-dialog>
<el-dialog title="修改" :visible.sync="editFormVisible">
<el-form ref="editForm" :model="editForm">
<el-form-item label="菜单编号" :label-width="formLabelWidth" prop="menuid">
<el-input v-model="editForm.menuid" autocomplete="off" readonly></el-input>
</el-form-item>
<el-form-item label="菜单名称" :label-width="formLabelWidth" prop="menuname">
<el-input v-model="editForm.menuname" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="访问地址" :label-width="formLabelWidth" prop="menuurl">
<el-input v-model="editForm.menuurl" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="父菜单" prop="qpid" :label-width="formLabelWidth">
<el-select v-model="editForm.pid" placeholder="pid">
<el-option label="无" :value="0"></el-option>
<el-option v-for="opt in selectOptions" :label="opt.menuname" :value="opt.menuid"></el-option>
</el-select>
</el-form-item>
<el-form-item label="图标" :label-width="formLabelWidth" prop="glyphicon">
<el-input v-model="editForm.glyphicon" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="editFormVisible = false">取 消</el-button>
<el-button type="primary" @click="editFormSubmit()">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
data() {
return {
tableData: [],
selectOptions:[],
/* pageinfo:
page: 1
pagesize: 10
total: 29 */
pageinfo:{
page: 3,
pagesize: 10,
total: 660
},
queryForm:{
qmname:'', //做双向绑定时,就不给假数据了,默认空值
qpid:''
},
/* String menuid = req.getParameter("menuid");
String menuname = req.getParameter("menuname");
String menuurl = req.getParameter("menuurl");
String pid = req.getParameter("pid");
String glyphicon = req.getParameter("glyphicon"); */
addForm:{
menuid:'',
menuname:'',
menuurl:'',
pid:'',
glyphicon:'',
},
editForm:{
menuid:'',
menuname:'',
menuurl:'',
pid:'',
glyphicon:'',
},
editFormVisible : false,
addFormVisible : false,
formLabelWidth: '120px',
currentRow: null
};
},
methods: {
editFormSubmit(){
this.editFormVisible = false; //让弹出框关闭
let url = "/menu/edit";
let params = this.$qs.stringify(this.editForm);
this.myCUD(url,params);
},
editFormOpen(){
this.editFormVisible = true;
//将选中行的数据对象填到editForm里
//this.editForm = this.currentRow; //这里实际只传了对象的引用,故editForm里的数据修改,页面数据也会改。他们指向同一个引用,并且做了数据双向绑定
//java里也有同样的问题,深克隆和浅克隆
//console.log(JSON.stringify(this.currentRow)); //json格式字符串化,且是标准的json格式
//console.log(JSON.parse(JSON.stringify(this.currentRow))); //将对象转成字符串,再转回来,就新创建了一个对象,虽然数据还是一样的
//this.editForm = this.currentRow; //用新的对象赋值给editForm。这就是js里的深克隆
this.editForm = JSON.parse(JSON.stringify(this.currentRow)); //可写成一句话
},
selectRowChange(val){ //参数是当前改变的这行数据
this.currentRow = val;
},
addFormOpen(formName){
this.addFormVisible = true;
this.$nextTick(function(){ //渲染时机后移,做完一次渲染后再执行括号里的代码
this.$refs[formName].resetFields();
})
},
addFormSubmit(){
this.addFormVisible = false; //让弹出框关闭
let url = "/menu/add";
let params = this.$qs.stringify(this.addForm);
this.myCUD(url,params);
},
resetForm(formname){
this.$refs[formname].resetFields();
},
queryMenu(){
let params = this.$qs.stringify(this.queryForm);
this.myQuery(params);
},
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
this.pageinfo.pagesize = val; //选中每页需要展示的页码数
this.pageinfo.page = 1; //切换pagesize之后,习惯将页数指定到第一页
let params = this.$qs.stringify(this.pageinfo)+"&"+this.$qs.stringify(this.queryForm);
console.log(params);
this.myQuery(params);
},
handleCurrentChange(val) { //页数发生改变触发该函数
console.log(`当前页: ${val}`); //可知当前要翻的页数
this.pageinfo.page = val; //将当前组件的page值设置成要翻页的页码
let params = this.$qs.stringify(this.pageinfo)+"&"+this.$qs.stringify(this.queryForm); //传一个pageinfo对象给后台,后端拿需要的参数即可
console.log(params); //先看一下这个参数
this.myQuery(params); //要加this,不加this就找外部的全局参数。
},
myCUD(url,params){
this.$axios.post(url,params)
.then((ret)=>{ //先和接口接通
//根据响应 提示操作的结果
if(ret.data.returnCode==10000){
this.$message({
message:ret.data.returnMsg,
type: 'success'
});
}else{
this.$message.error(ret.data.returnMsg);
}
//刷新数据
let params = this.$qs.stringify(this.pageinfo)+"&"+this.$qs.stringify(this.queryForm);
this.myQuery(params);
//刷新下拉列表数据:
this.getMenuSelect();
}).catch((err)=>{
})
},
myQuery(params){
this.$axios.get("/menu/query?"+params)
.then((ret)=>{
console.log(ret);
if(ret.data.returnCode==10000){
//展示table数据
this.tableData = ret.data.returnData;
//把页码相关数据传给分页组件
this.pageinfo = ret.data.pageinfo;
}
}).catch((err)=>{
console.log(err);
});
},
getMenuSelect(){
this.$axios.get("/menu/getmenuselect")
.then((ret)=>{
console.log(ret);
if(ret.data.returnCode==10000){
//展示table数据
this.selectOptions = ret.data.returnData;
}
}).catch((err)=>{
console.log(err);
});
}
},
mounted(){
console.log("页面加载结束后执行");
let params = "";
this.myQuery(params);
this.getMenuSelect();
}
}
</script>
<style>
.el-select{
width:100%;
}
</style>
效果如下:

1.3.4删除功能
定位一条数据(已有),并做一个删除数据的展示(不用弹出框)。
①.复制小弹出框的代码
elementUI里的Notice里的MessageBox的确认信息.
添加进按钮:
<el-button type="danger" @click="removeMenu()">删除</el-button>
将removeMenu()方法添加:
removeMenu(){
this.$confirm('此操作将删除编号为 '+this.currentRow.menuid+' 的记录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => { //表示成功,即点击了确定按钮
this.$message({
type: 'success',
message: '删除成功!'
});
}).catch(() => { //表示失败
this.$message({
type: 'info',
message: '已取消删除'
});
});
}
点击确定按钮后的内容自己改下:
应该将要删除的id传到后台的删除接口
删除完还是刷新对应的数据。
removeMenu(){
this.$confirm('此操作将删除编号为 '+this.currentRow.menuid+' 的记录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => { //表示成功,即点击了确定按钮
//把id发到后台删除
console.log(this.currentRow.menuid);
let url = "/menu/remove";
let params = "menuid="+this.currentRow.menuid;
this.myCUD(url,params);
}).catch(() => { //表示失败
this.$message({
type: 'info',
message: '已取消删除'
});
});
}
单个模块的增删改查就写完了。
代码如下:
<template>
<div>
<el-form ref="queryForm" :inline="true" :model="queryForm" class="demo-form-inline">
<el-form-item label="菜单名称" prop="qmname">
<el-input v-model="queryForm.qmname" placeholder="menuname"></el-input>
</el-form-item>
<el-form-item label="父菜单" prop="qpid">
<el-select v-model="queryForm.qpid" placeholder="pid">
<el-option label="无" value="0"></el-option>
<el-option v-for="opt in selectOptions" :label="opt.menuname" :value="opt.menuid"></el-option>
</el-select>
</el-form-item>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="queryMenu()">查询</el-button>
<el-button type="info" plain @click="resetForm('queryForm')">重置</el-button>
<el-button type="success" @click="addFormOpen('addForm')">添加</el-button>
<el-button type="warning" @click="editFormOpen('editForm')">修改</el-button>
<el-button type="danger" @click="removeMenu()">删除</el-button>
</el-form-item>
</el-form>
<el-table
:data="tableData"
highlight-current-row
@current-change="selectRowChange"
style="width: 100%">
<el-table-column
prop="menuid"
label="菜单编号">
</el-table-column>
<el-table-column
prop="menuname"
label="菜单名称">
</el-table-column>
<el-table-column
prop="menuurl"
label="访问地址">
</el-table-column>
<el-table-column
prop="pid"
label="上级菜单编号">
</el-table-column>
<el-table-column
prop="pname"
label="上级菜单名称">
</el-table-column>
<el-table-column label="菜单图标">
<template v-slot="mydata">
<i :class="mydata.row.glyphicon"></i>{{mydata.row.glyphicon}}
</template>
</el-table-column>
</el-table>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageinfo.page"
:page-sizes="[10, 20, 30]"
:page-size="pageinfo.pagesize"
layout="total, sizes, prev, pager, next, jumper"
:total="pageinfo.total">
</el-pagination>
<!-- String menuid = req.getParameter("menuid");
String menuname = req.getParameter("menuname");
String menuurl = req.getParameter("menuurl");
String pid = req.getParameter("pid");
String glyphicon = req.getParameter("glyphicon"); -->
<el-dialog title="添加" :visible.sync="addFormVisible">
<el-form ref="addForm" :model="addForm">
<el-form-item label="菜单编号" :label-width="formLabelWidth" prop="menuid">
<el-input v-model="addForm.menuid" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="菜单名称" :label-width="formLabelWidth" prop="menuname">
<el-input v-model="addForm.menuname" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="访问地址" :label-width="formLabelWidth" prop="menuurl">
<el-input v-model="addForm.menuurl" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="父菜单" prop="qpid" :label-width="formLabelWidth">
<el-select v-model="addForm.pid" placeholder="pid">
<el-option label="无" value="0"></el-option>
<el-option v-for="opt in selectOptions" :label="opt.menuname" :value="opt.menuid"></el-option>
</el-select>
</el-form-item>
<el-form-item label="图标" :label-width="formLabelWidth" prop="glyphicon">
<el-input v-model="addForm.glyphicon" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="addFormVisible = false">取 消</el-button>
<el-button type="primary" @click="addFormSubmit()">确 定</el-button>
</div>
</el-dialog>
<el-dialog title="修改" :visible.sync="editFormVisible">
<el-form ref="editForm" :model="editForm">
<el-form-item label="菜单编号" :label-width="formLabelWidth" prop="menuid">
<el-input v-model="editForm.menuid" autocomplete="off" readonly></el-input>
</el-form-item>
<el-form-item label="菜单名称" :label-width="formLabelWidth" prop="menuname">
<el-input v-model="editForm.menuname" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="访问地址" :label-width="formLabelWidth" prop="menuurl">
<el-input v-model="editForm.menuurl" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="父菜单" prop="qpid" :label-width="formLabelWidth">
<el-select v-model="editForm.pid" placeholder="pid">
<el-option label="无" :value="0"></el-option>
<el-option v-for="opt in selectOptions" :label="opt.menuname" :value="opt.menuid"></el-option>
</el-select>
</el-form-item>
<el-form-item label="图标" :label-width="formLabelWidth" prop="glyphicon">
<el-input v-model="editForm.glyphicon" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="editFormVisible = false">取 消</el-button>
<el-button type="primary" @click="editFormSubmit()">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
data() {
return {
tableData: [],
selectOptions:[],
/* pageinfo:
page: 1
pagesize: 10
total: 29 */
pageinfo:{
page: 3,
pagesize: 10,
total: 660
},
queryForm:{
qmname:'', //做双向绑定时,就不给假数据了,默认空值
qpid:''
},
/* String menuid = req.getParameter("menuid");
String menuname = req.getParameter("menuname");
String menuurl = req.getParameter("menuurl");
String pid = req.getParameter("pid");
String glyphicon = req.getParameter("glyphicon"); */
addForm:{
menuid:'',
menuname:'',
menuurl:'',
pid:'',
glyphicon:'',
},
editForm:{
menuid:'',
menuname:'',
menuurl:'',
pid:'',
glyphicon:'',
},
editFormVisible : false,
addFormVisible : false,
formLabelWidth: '120px',
currentRow: null
};
},
methods: {
removeMenu(){
this.$confirm('此操作将删除编号为 '+this.currentRow.menuid+' 的记录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => { //表示成功,即点击了确定按钮
//把id发到后台删除
console.log(this.currentRow.menuid);
let url = "/menu/remove";
let params = "menuid="+this.currentRow.menuid;
this.myCUD(url,params);
}).catch(() => { //表示失败
this.$message({
type: 'info',
message: '已取消删除'
});
});
},
editFormSubmit(){
this.editFormVisible = false; //让弹出框关闭
let url = "/menu/edit";
let params = this.$qs.stringify(this.editForm);
this.myCUD(url,params);
},
editFormOpen(){
this.editFormVisible = true;
//将选中行的数据对象填到editForm里
//this.editForm = this.currentRow; //这里实际只传了对象的引用,故editForm里的数据修改,页面数据也会改。他们指向同一个引用,并且做了数据双向绑定
//java里也有同样的问题,深克隆和浅克隆
//console.log(JSON.stringify(this.currentRow)); //json格式字符串化,且是标准的json格式
//console.log(JSON.parse(JSON.stringify(this.currentRow))); //将对象转成字符串,再转回来,就新创建了一个对象,虽然数据还是一样的
//this.editForm = this.currentRow; //用新的对象赋值给editForm。这就是js里的深克隆
this.editForm = JSON.parse(JSON.stringify(this.currentRow)); //可写成一句话
},
selectRowChange(val){ //参数是当前改变的这行数据
this.currentRow = val;
},
addFormOpen(formName){
this.addFormVisible = true;
this.$nextTick(function(){ //渲染时机后移,做完一次渲染后再执行括号里的代码
this.$refs[formName].resetFields();
})
},
addFormSubmit(){
this.addFormVisible = false; //让弹出框关闭
let url = "/menu/add";
let params = this.$qs.stringify(this.addForm);
this.myCUD(url,params);
},
resetForm(formname){
this.$refs[formname].resetFields();
},
queryMenu(){
let params = this.$qs.stringify(this.queryForm);
this.myQuery(params);
},
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
this.pageinfo.pagesize = val; //选中每页需要展示的页码数
this.pageinfo.page = 1; //切换pagesize之后,习惯将页数指定到第一页
let params = this.$qs.stringify(this.pageinfo)+"&"+this.$qs.stringify(this.queryForm);
console.log(params);
this.myQuery(params);
},
handleCurrentChange(val) { //页数发生改变触发该函数
console.log(`当前页: ${val}`); //可知当前要翻的页数
this.pageinfo.page = val; //将当前组件的page值设置成要翻页的页码
let params = this.$qs.stringify(this.pageinfo)+"&"+this.$qs.stringify(this.queryForm); //传一个pageinfo对象给后台,后端拿需要的参数即可
console.log(params); //先看一下这个参数
this.myQuery(params); //要加this,不加this就找外部的全局参数。
},
myCUD(url,params){
this.$axios.post(url,params)
.then((ret)=>{ //先和接口接通
//根据响应 提示操作的结果
if(ret.data.returnCode==10000){
this.$message({
message:ret.data.returnMsg,
type: 'success'
});
}else{
this.$message.error(ret.data.returnMsg);
}
//刷新数据
let params = this.$qs.stringify(this.pageinfo)+"&"+this.$qs.stringify(this.queryForm);
this.myQuery(params);
//刷新下拉列表数据:
this.getMenuSelect();
}).catch((err)=>{
})
},
myQuery(params){
this.$axios.get("/menu/query?"+params)
.then((ret)=>{
console.log(ret);
if(ret.data.returnCode==10000){
//展示table数据
this.tableData = ret.data.returnData;
//把页码相关数据传给分页组件
this.pageinfo = ret.data.pageinfo;
}
}).catch((err)=>{
console.log(err);
});
},
getMenuSelect(){
this.$axios.get("/menu/getmenuselect")
.then((ret)=>{
console.log(ret);
if(ret.data.returnCode==10000){
//展示table数据
this.selectOptions = ret.data.returnData;
}
}).catch((err)=>{
console.log(err);
});
}
},
mounted(){
console.log("页面加载结束后执行");
let params = "";
this.myQuery(params);
this.getMenuSelect();
}
}
</script>
<style>
.el-select{
width:100%;
}
</style>
1.3.5最后一个功能
修改和删除按钮,只有选中记录才会生效。不选中直接点会报错,这里优化一下。
没选中记录,这两个按钮禁用。
这两个按钮的disabled属性本来是true,点击一行之后变成false。
需要属性绑定的方式去写。
先加两个disabled的属性:
<el-button type="warning" @click="editFormOpen('editForm')" :disabled="btnstatus">修改</el-button>
<el-button type="danger" @click="removeMenu()" :disabled="btnstatus">删除</el-button>
在data里增加:
btnstatus:true
点击一行能用,找selectRowChange函数,
selectRowChange(val){ //参数是当前改变的这行数据
this.currentRow = val;
this.btnstatus = false;
}
使用vue之后,如何考虑页面效果的切换。做页面绑定。
现在翻页之后,按钮还可以选择,应该变回true。选择每页的记录数后,也应该变为true。
也就是凡是页面重新查询后,按钮都该禁用。
myQuery(params){
this.$axios.get("/menu/query?"+params)
.then((ret)=>{
console.log(ret);
if(ret.data.returnCode==10000){
this.btnstatus = true; //按钮禁用
//展示table数据
this.tableData = ret.data.returnData;
//把页码相关数据传给分页组件
this.pageinfo = ret.data.pageinfo;
}
}).catch((err)=>{
console.log(err);
});
}
好像不太好用,有时候可行,有时候不行。
还是渲染时机问题。
this.$nextTick(function(){
this.btnstatus = true; //按钮禁用
})
现在不好使了。
因为nextTick只是把渲染时机后移,具体移到哪次渲染之后没法控制。
现在使用vue的监控机制,可精确找到代码要执行的时机。
数据刷新时,会取消掉选中的行,也就是table重新生成的时候。
watch:{ //监控指定的数据
tableData:function(){ //刷新数据后自动触发
console.log("tableData数据渲染完成了");
this.$nextTick(function(){
this.btnstatus = true; //按钮禁用
})
}
}
和mounted(钩子函数)是同级的。
最终的代码:
<template>
<div>
<el-form ref="queryForm" :inline="true" :model="queryForm" class="demo-form-inline">
<el-form-item label="菜单名称" prop="qmname">
<el-input v-model="queryForm.qmname" placeholder="menuname"></el-input>
</el-form-item>
<el-form-item label="父菜单" prop="qpid">
<el-select v-model="queryForm.qpid" placeholder="pid">
<el-option label="无" value="0"></el-option>
<el-option v-for="opt in selectOptions" :label="opt.menuname" :value="opt.menuid"></el-option>
</el-select>
</el-form-item>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="queryMenu()">查询</el-button>
<el-button type="info" plain @click="resetForm('queryForm')">重置</el-button>
<el-button type="success" @click="addFormOpen('addForm')">添加</el-button>
<el-button type="warning" @click="editFormOpen('editForm')" :disabled="btnstatus">修改</el-button>
<el-button type="danger" @click="removeMenu()" :disabled="btnstatus">删除</el-button>
</el-form-item>
</el-form>
<el-table
:data="tableData"
highlight-current-row
@current-change="selectRowChange"
style="width: 100%">
<el-table-column
prop="menuid"
label="菜单编号">
</el-table-column>
<el-table-column
prop="menuname"
label="菜单名称">
</el-table-column>
<el-table-column
prop="menuurl"
label="访问地址">
</el-table-column>
<el-table-column
prop="pid"
label="上级菜单编号">
</el-table-column>
<el-table-column
prop="pname"
label="上级菜单名称">
</el-table-column>
<el-table-column label="菜单图标">
<template v-slot="mydata">
<i :class="mydata.row.glyphicon"></i>{{mydata.row.glyphicon}}
</template>
</el-table-column>
</el-table>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageinfo.page"
:page-sizes="[10, 20, 30]"
:page-size="pageinfo.pagesize"
layout="total, sizes, prev, pager, next, jumper"
:total="pageinfo.total">
</el-pagination>
<!-- String menuid = req.getParameter("menuid");
String menuname = req.getParameter("menuname");
String menuurl = req.getParameter("menuurl");
String pid = req.getParameter("pid");
String glyphicon = req.getParameter("glyphicon"); -->
<el-dialog title="添加" :visible.sync="addFormVisible">
<el-form ref="addForm" :model="addForm">
<el-form-item label="菜单编号" :label-width="formLabelWidth" prop="menuid">
<el-input v-model="addForm.menuid" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="菜单名称" :label-width="formLabelWidth" prop="menuname">
<el-input v-model="addForm.menuname" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="访问地址" :label-width="formLabelWidth" prop="menuurl">
<el-input v-model="addForm.menuurl" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="父菜单" prop="qpid" :label-width="formLabelWidth">
<el-select v-model="addForm.pid" placeholder="pid">
<el-option label="无" value="0"></el-option>
<el-option v-for="opt in selectOptions" :label="opt.menuname" :value="opt.menuid"></el-option>
</el-select>
</el-form-item>
<el-form-item label="图标" :label-width="formLabelWidth" prop="glyphicon">
<el-input v-model="addForm.glyphicon" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="addFormVisible = false">取 消</el-button>
<el-button type="primary" @click="addFormSubmit()">确 定</el-button>
</div>
</el-dialog>
<el-dialog title="修改" :visible.sync="editFormVisible">
<el-form ref="editForm" :model="editForm">
<el-form-item label="菜单编号" :label-width="formLabelWidth" prop="menuid">
<el-input v-model="editForm.menuid" autocomplete="off" readonly></el-input>
</el-form-item>
<el-form-item label="菜单名称" :label-width="formLabelWidth" prop="menuname">
<el-input v-model="editForm.menuname" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="访问地址" :label-width="formLabelWidth" prop="menuurl">
<el-input v-model="editForm.menuurl" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="父菜单" prop="qpid" :label-width="formLabelWidth">
<el-select v-model="editForm.pid" placeholder="pid">
<el-option label="无" :value="0"></el-option>
<el-option v-for="opt in selectOptions" :label="opt.menuname" :value="opt.menuid"></el-option>
</el-select>
</el-form-item>
<el-form-item label="图标" :label-width="formLabelWidth" prop="glyphicon">
<el-input v-model="editForm.glyphicon" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="editFormVisible = false">取 消</el-button>
<el-button type="primary" @click="editFormSubmit()">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
data() {
return {
tableData: [],
selectOptions:[],
/* pageinfo:
page: 1
pagesize: 10
total: 29 */
pageinfo:{
page: 3,
pagesize: 10,
total: 660
},
queryForm:{
qmname:'', //做双向绑定时,就不给假数据了,默认空值
qpid:''
},
/* String menuid = req.getParameter("menuid");
String menuname = req.getParameter("menuname");
String menuurl = req.getParameter("menuurl");
String pid = req.getParameter("pid");
String glyphicon = req.getParameter("glyphicon"); */
addForm:{
menuid:'',
menuname:'',
menuurl:'',
pid:'',
glyphicon:'',
},
editForm:{
menuid:'',
menuname:'',
menuurl:'',
pid:'',
glyphicon:'',
},
editFormVisible : false,
addFormVisible : false,
formLabelWidth: '120px',
currentRow: null,
btnstatus:true
};
},
methods: {
removeMenu(){
this.$confirm('此操作将删除编号为 '+this.currentRow.menuid+' 的记录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => { //表示成功,即点击了确定按钮
//把id发到后台删除
console.log(this.currentRow.menuid);
let url = "/menu/remove";
let params = "menuid="+this.currentRow.menuid;
this.myCUD(url,params);
}).catch(() => { //表示失败
this.$message({
type: 'info',
message: '已取消删除'
});
});
},
editFormSubmit(){
this.editFormVisible = false; //让弹出框关闭
let url = "/menu/edit";
let params = this.$qs.stringify(this.editForm);
this.myCUD(url,params);
},
editFormOpen(){
this.editFormVisible = true;
//将选中行的数据对象填到editForm里
//this.editForm = this.currentRow; //这里实际只传了对象的引用,故editForm里的数据修改,页面数据也会改。他们指向同一个引用,并且做了数据双向绑定
//java里也有同样的问题,深克隆和浅克隆
//console.log(JSON.stringify(this.currentRow)); //json格式字符串化,且是标准的json格式
//console.log(JSON.parse(JSON.stringify(this.currentRow))); //将对象转成字符串,再转回来,就新创建了一个对象,虽然数据还是一样的
//this.editForm = this.currentRow; //用新的对象赋值给editForm。这就是js里的深克隆
this.editForm = JSON.parse(JSON.stringify(this.currentRow)); //可写成一句话
},
selectRowChange(val){ //参数是当前改变的这行数据
this.currentRow = val;
this.btnstatus = false;
},
addFormOpen(formName){
this.addFormVisible = true;
this.$nextTick(function(){ //渲染时机后移,做完一次渲染后再执行括号里的代码
this.$refs[formName].resetFields();
})
},
addFormSubmit(){
this.addFormVisible = false; //让弹出框关闭
let url = "/menu/add";
let params = this.$qs.stringify(this.addForm);
this.myCUD(url,params);
},
resetForm(formname){
this.$refs[formname].resetFields();
},
queryMenu(){
let params = this.$qs.stringify(this.queryForm);
this.myQuery(params);
},
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
this.pageinfo.pagesize = val; //选中每页需要展示的页码数
this.pageinfo.page = 1; //切换pagesize之后,习惯将页数指定到第一页
let params = this.$qs.stringify(this.pageinfo)+"&"+this.$qs.stringify(this.queryForm);
console.log(params);
this.myQuery(params);
},
handleCurrentChange(val) { //页数发生改变触发该函数
console.log(`当前页: ${val}`); //可知当前要翻的页数
this.pageinfo.page = val; //将当前组件的page值设置成要翻页的页码
let params = this.$qs.stringify(this.pageinfo)+"&"+this.$qs.stringify(this.queryForm); //传一个pageinfo对象给后台,后端拿需要的参数即可
console.log(params); //先看一下这个参数
this.myQuery(params); //要加this,不加this就找外部的全局参数。
},
myCUD(url,params){
this.$axios.post(url,params)
.then((ret)=>{ //先和接口接通
//根据响应 提示操作的结果
if(ret.data.returnCode==10000){
this.$message({
message:ret.data.returnMsg,
type: 'success'
});
}else{
this.$message.error(ret.data.returnMsg);
}
//刷新数据
let params = this.$qs.stringify(this.pageinfo)+"&"+this.$qs.stringify(this.queryForm);
this.myQuery(params);
//刷新下拉列表数据:
this.getMenuSelect();
}).catch((err)=>{
})
},
myQuery(params){
this.$axios.get("/menu/query?"+params)
.then((ret)=>{
console.log(ret);
if(ret.data.returnCode==10000){
/* this.$nextTick(function(){
this.btnstatus = true; //按钮禁用
}) */
//展示table数据
this.tableData = ret.data.returnData;
//把页码相关数据传给分页组件
this.pageinfo = ret.data.pageinfo;
}
}).catch((err)=>{
console.log(err);
});
},
getMenuSelect(){
this.$axios.get("/menu/getmenuselect")
.then((ret)=>{
console.log(ret);
if(ret.data.returnCode==10000){
//展示table数据
this.selectOptions = ret.data.returnData;
}
}).catch((err)=>{
console.log(err);
});
}
},
mounted(){
console.log("页面加载结束后执行");
let params = "";
this.myQuery(params);
this.getMenuSelect();
},
watch:{ //监控指定的数据
tableData:function(){ //刷新数据后自动触发
console.log("tableData数据渲染完成了");
this.$nextTick(function(){
this.btnstatus = true; //按钮禁用
})
}
}
}
</script>
<style>
.el-select{
width:100%;
}
</style>
2134

被折叠的 条评论
为什么被折叠?



