Vue框架教程-从入门到项目实战
创建Vue项目
我们通过vue-cli创建一个vue项目,
- 在cmd窗口输入 vue ui 进入vue-cli可视化界面(如果无效请升级vue-cli版本)
- 点击创建,选择一个项目目录
- 输入项目名称和git初始化窗口(可选)
- 选择预设,可以选择手动和预定的设置 (预设就是一套定义好的插件和配置。 你也可以将自己的配置保存成预设,方便以后创建项目使用。)
- 选择项目功能(也可以在创建后手动添加)
- 选择配置
- 等待创建完项目即可(如果是第一次可能有点慢)
- 启动项目
引入Element-Ui
- 点击左侧插件,点击右上角添加插件
- 点击所有插件,输入element,选中第一个,点击创建
- 配置插件,点击手工按需导入,选中zh-cn中文,完成按照即可
手动引入组件
或者导入一行
Git上传仓库
我们的代码一般都会上传到Gitee或者GitHub中的远程仓库托管,这样我们电脑项目丢失或者需要旧版本的项目可以直接将远程的代码下载(拉取)到本地进行开发。
- 我们先安装Git软件 https://git-scm.com/
- 前往Gitee注册账号https://gitee.com/
- 配置SSH公钥,点击怎么生成公钥然后按照步骤进行申请
在CMD窗口输入上方黄色指令进行生成,其中的”xxx“改成注册的邮箱
如果cmd窗口生成失败,进入桌面鼠标右键点击Git GUl Here
点击show ssh key,将生成key的指令粘贴进去弹出账号密码输入gitee注册的账号密码即可生成完成
生成完成后第三步的公钥取和输入自定义标题即可完成添加公钥
新建仓库
输入仓库名称选择开源或者私有即可,点击创建
将创建的vue项目上传到刚刚创建的仓库中,我们初始化一下Git(一定要执行)
我们cd 进入vue项目的更目录查询一下项目是否干净
我们将当前下的文件提交到本地的git中,
然后我们在执行一个 git status,显示当前分支和目录处于干净状态
- 我们将本地的git上传到远程gitee仓库,先复制黄色内容,在刚刚的cmd中执行一下,表示上传成功
- 最后我们刷新一个我们的仓库,就可以看见我们项目了
创建新的分支
我们在添加新功能的时候会创建一个分支
git checkout -b login
PS D:\heima_shop\xcwl_shop> git checkout -b login
Switched to a new branch 'login'
PS D:\heima_shop\xcwl_shop>
查看所有分支
git branch
vscode从远程仓库拉代码
1,在你写项目的磁盘里新建文件夹
2,登录Gitee
3,复制克隆/下载处的地址
4,打开VScode,在新建的文件夹下,打开终端
5,运行 git clone + 地址 ,回车,项目就拉取下来了
提交代码
将本地代码提交到Git仓库
- 获取当前文件(跟仓库代码做对比,那些修改过,那些是新增的)
- git add . 将代码全部添加在暂存区
- git commit -m “完成了登录功能” 将代码提交到本地git仓库
- 合并分支,获取当前分支:git branch,切换到主分支git checkout master
- 当前在主分支输入命令git merge login 将login分支合并到当前主分支
- 当前login分支的代码已经全部合并到主分支了,我们将主分支代码同步到gitee仓库通过 git push命令
- 在gitee仓库创建一个子分支,git push -u origin login,创建了一个login子分支
Vue
axios
注意:要先下载引入axios组件
在main.js中引入,即可全局使用
本地存储Token
//1.将登录成功之后的Token存放到客户端的sessionStorage中,为什么不存放到localstorage中呢,因为他是持久性机制,sessionstorage是会话机制//1.1项目中除了登录之外的其他API接口,必须在登录之后才能访问//1.2token只能在当前网站打开期间生效,所以将token存放在sessionstorage中window.sessionStorage.setItem("token", req.data.data);//2.通过编程式导航跳转到后台首页,路由地址是/homethis.$router.push("/home");
路由导航守卫
//路由守卫,在执行路由前执行本方法来做认证操作
// to:要去的路径,from:获取从那个页面路径跳转而来的,next:放行
router.beforeEach((to,from,next)=>{// 判断当前路径是否为login ,如果是true 着放行if(to.path==="/login") return next();//获取当前tokenconst token=window.sessionStorage.getItem("token");//如果当前token为空,着返回到login页面if(!token)return next("/login");//如果上面全部都过了,那么执行放行next();
})
配置请求token
我们在除了登录和注册接口中不需要携带token,但是其他所有的请求中必须要携带token来确保当前账户,
如果我们每个axios中手动在head中添加会很麻烦,所以我们定义一个全局的拦截器
在每次请求的方法中,会先调用我们定义的全局拦截器,在继续执行我们的请求接口
//通过调用axios中的interceptors属性中的request成员(请求拦截器)中的use函数来添加全局请求头
axios.interceptors.request.use(config =>{//通过返回的config对象中的headers属性添加一个Authorization=本地存储的tokenconfig.headers.Authorization=window.sessionStorage.getItem("token")//在最后必须teturn configreturn config
})
作用域插槽
可以定义一个插槽,切插槽可以获取当前对象
<el-table-column label="状态"><!-- 我们创建一个作用域插槽模板来写一个开关按钮 通过slot-scope="scope"来接收当前一行对象数据--><template slot-scope="scope"><!-- 可以通过scope.row获取当前一行对象,通过.对象中的参数可以获取对应的值 -->{{ scope.row.mg_state }}<!-- 定义一个开关按钮,v-mode的值为true,false,对应开还是关 --><el-switch v-model="scope.row.mg_state"> </el-switch></template></el-table-column>
字符串 数组转换
数组转字符串用.join()方法不填参数表示转换已,分割 a,b,c 填参数 .join(“.”) 打印 a.b.c
Css
在创建vue项目中,页面样式默认都是有margin和padding所以我们创建一个全局css样式表来设置全部页面的默认样式
在assets下创建css文件在创建一个global.css文件
/* 全局css样式 */
html,body,#app{height: 100%;margin: 0px;padding: 0px;
}
flex布局
/*设置布局方式为flex*/ display: flex;
/*设置靠右对齐*/ justify-content: space-between;
/*设置上下居中*/align-items: center;
class绑定多css
:class="['borderbottom','vcenter']"
class做判断
功能实现
退出功能
退出功能原理详解
基于token的方式实现退出比较简单,只需要将本地存储的token销毁掉,这样后续的请求就不会携带token并且路由守卫也获取不到存储的token就会被拦截强制跳转到login登录页面,必须重新登录才可以获取新的token存储到本地就可以访问其他页面
<template><div><el-button type="info" @click="tuichu">退出</el-button></div>
</template>
<script>
export default {methods:{tuichu(){//获取本地的sessionStorage执行remove方法清除tokenwindow.sessionStorage.removeItem("token");//通过路由puth跳转(重定向)到login登录界面this.$router.push("/login");}}
}
</script>
<style scoped></style>
首页布局
Head头部
<template><!-- 创建布局容器 --><el-container class="home-container"><!-- 头部 --><el-header><div class="header-div"><imgsrc="../assets/logo.png"alt=""style="height: 50px; width: 50px"/><!-- 设置跟图片间隔15px --><span style="margin-left: 15px">电商后台管理系统</span></div><el-button type="info" @click="tuichu">退出</el-button></el-header><!-- 内容主体区域 --><el-container><!-- 内容主体左侧侧边栏 --><el-aside width="200px">Aside</el-aside><!-- 内容主体右侧内容 --><el-main>Main</el-main></el-container></el-container>
</template>
<script>
export default {methods: {tuichu() {// 获取本地的sessionStorage执行remove方法清除tokenwindow.sessionStorage.removeItem("token")// 通过路由puth跳转到login登录界面this.$router.push("/login")},},
}
</script>
<style scoped>
/* 给容器设置宽高 */
.home-container {height: 100%;width: 100%;
}.el-header {background-color: #373d41;/* 设置flex布局方式 */display: flex;/* 靠右对齐 */justify-content: space-between;padding-left: 0;/* 设置上下居中 */align-items: center;color: #fff;font-size: 20px;
}
.header-div {/* 设置flex布局方式 */display: flex;/* 设置居中对其 */align-items: center;
}.el-aside {background-color: #333744;
}
.el-main {background-color: #eaedf1;
}
</style>
左侧侧边栏
<el-aside width="200px"><!-- 侧边栏内容区域 --><el-menubackground-color="rgb(51,55,68)"text-color="#fff"active-text-color="#ffd04b"><!-- 一级菜单 --><el-submenu index="1"><!-- 一级菜单模板区域 --><template slot="title"><!-- 菜单图标 --><i class="el-icon-location"></i><!-- 采单文本 --><span>导航一</span></template><!-- 二级菜单 --><el-menu-item index="1-4-1"><!-- 二级菜单模板区域 --><template slot="title"><!-- 菜单图标 --><i class="el-icon-location"></i><!-- 菜单文本 --><span>导航一</span></template></el-menu-item></el-submenu></el-menu></el-aside>
获取侧边栏数据,并且渲染到页面
<template><!-- 创建布局容器 --><el-container class="home-container"><!-- 头部 --><el-header><div class="header-div"><imgsrc="../assets/logo.png"alt=""style="height: 50px; width: 50px"/><!-- 设置跟图片间隔15px --><span style="margin-left: 15px">电商后台管理系统</span></div><el-button type="info" @click="tuichu">退出</el-button></el-header><!-- 内容主体区域 --><el-container><!-- 内容主体左侧侧边栏 --><el-aside width="200px"><!-- 侧边栏内容区域 --><el-menubackground-color="rgb(51,55,68)"text-color="#fff"active-text-color="#ffd04b"><!-- 一级菜单 --><el-submenu :index="''+item.id" v-for="(item, index) in meaunList" :key="index"><!-- 一级菜单模板区域 --><template slot="title"><!-- 菜单图标 --><i class="el-icon-location"></i><!-- 采单文本 --><span>{{item.authName}}</span></template><!-- 二级菜单 --><el-menu-item :index="''+item.children[0].id"><!-- 二级菜单模板区域 --><template slot="title"><!-- 菜单图标 --><i class="el-icon-location"></i><!-- 菜单文本 --><span>{{item.children[0].authName}}</span></template></el-menu-item></el-submenu></el-menu></el-aside><!-- 内容主体右侧内容 --><el-main>Main</el-main></el-container></el-container>
</template>
<script>
export default {data(){return{meaunList: [],}},// created:生命周期函数,在进入页面时先加载这个函数在加载html....// created跟mounted有什么区别呢? created加载完在加载html,mounted是html加载完在执行mounted,所以created的执行优先级比mounted高//this.getMenuList()来获取axios返回的菜单数据created() {this.getMenuList()},methods: {tuichu() {// 获取本地的sessionStorage执行remove方法清除tokenwindow.sessionStorage.removeItem("token")// 通过路由puth跳转到login登录界面this.$router.push("/login")},//获取所有的菜单async getMenuList() {//变量名{data:req}这样写可以直接获取请求对象中的data属性 ,变量名称为reqconst { data: req } = await this.$http.get("/menus")// console.log(req);// const data = await this.$http.get("/menus")// 判断是否获取成功,如果失败返回失败信息if (req.meta.status !== 200) return this.$message.error(req.meta.msg)//成功后将菜单信息定义到data数组this.meaunList = req.data},},
}
</script>
<style scoped>
/* 给容器设置宽高 */
.home-container {height: 100%;width: 100%;
}.el-header {background-color: #373d41;/* 设置flex布局方式 */display: flex;/* 靠右对齐 */justify-content: space-between;padding-left: 0;/* 设置上下居中 */align-items: center;color: #fff;font-size: 20px;
}
.header-div {/* 设置flex布局方式 */display: flex;/* 设置居中对其 */align-items: center;
}.el-aside {background-color: #333744;
}
.el-main {background-color: #eaedf1;
}
</style>
侧边栏美化
.el-submenu {/* 给菜单图标设置间距 */margin-right: 10px;
}
.el-menu {/* 将侧边栏默认的边框去掉 */border-right: none;
}
给手动设置图标icon
侧边栏伸缩
侧边栏点击收缩,点击展开,其实就是定义一个点击事件然后修改侧边栏的collapse属性为true或者false
<!-- 定义展开伸缩点击事件 --><div class="toggle-button" @click="toggleCollapse">|||</div><el-menubackground-color="rgb(51,55,68)"text-color="#fff"active-text-color="#409eff"<!-- 是否只保持一个子菜单的展开 -->unique-opened<!-- 是否水平折叠收起菜单 这里调用的是toggleCollapse方法,如果方法里面有本方法会优先调用方法其次在调用data中的-->:collapse="iscollapse"<!-- 是否开启折叠动画 这里调用的是data中的transition-->:collapse-transition="transition">
</el-menu>
data() {return {// 是否折叠iscollapse:false,//是否开启折叠动画transition:false}}
// 点击按钮,切换菜单显示和展开toggleCollapse() {this.iscollapse=!this.iscollapse},
实现路由重定向
我们在登录login成功后跳转到我们home页面,会默认加载welcome页面(这里使用重定向)
我们先将welcome页面注册到home子路由中
{path: "/Home",name: "Home",component: () => import("../components/Home.vue"),// 默认页面时重定向/welcome子路由页面redirect: "/welcome",//注册子路由,主路由页面中可以随时切换到子路由页面,切换到那个区域由router-view标签决定children: [{path: "/welcome",name: "welcome",component: () => import("../components/Welcome.vue"),},],},
将子路由页面加载到home主路由那个区域?在主路由用router-view来决定
<!-- 内容主体右侧内容 --><el-main><!--定义到这里--><router-view></router-view></el-main>
导航栏小bug
我们点击二级菜单后虽然有高亮,但是刷新后就没有高亮了,
我们可以通过default-active=“二级菜单路径” 来定义高亮
解决方法:
我们在点击二级菜单时将path路径保存进sessionstora中,在将存放在sessiostora中的path路径赋值给default-active即可
<el-menu//设置二级菜单高亮//这里的active对应的时data中的active:default-active="active"><!-- 二级菜单 --><el-menu-itemv-for="(item, index) in item.children":index="'/' + item.path":key="index"//定义一个点击方法将path传递过去@click="setactive('/' + item.path)">data(){return{// 获取本地存储的上次点击的菜单栏active:window.sessionStorage.getItem("active"),} }
//点击后执行本方法,将path存放进sessionstora中setactive(active) {window.sessionStorage.setItem("active", active)},
用户列表
因为每个页面都有面包屑导航栏,而且还跟卡片面板挨得太近,在全局css样式中添加样式
/* 面包屑 */
.el-breadcrumb{margin-bottom: 15px;font-size: 12px;
}
/* 卡片面板 */
.el-card{/* 设置卡片阴影 */box-shadow: 0,1px,1px rgb(0, 0,0, 0.15);
}
面包屑
<!-- 面包屑导航 --><el-breadcrumb separator-class="el-icon-arrow-right"><!--点击即可回到home首页--><el-breadcrumb-item :to="{ path: '/Home' }">首页</el-breadcrumb-item><el-breadcrumb-item>用户管理</el-breadcrumb-item><el-breadcrumb-item>用户列表</el-breadcrumb-item></el-breadcrumb>
卡片面板
<!-- 卡片试图区 --><el-card class="box-card"><!-- 设置两栏间距 --><el-row :gutter="20"><!-- 设置这一栏大小 --><el-col :span="8"><!-- 搜索与添加区域 --><el-input placeholder="请输入内容"><el-button slot="append" icon="el-icon-search"></el-button></el-input></el-col><el-col :span="4"><!-- 按钮 --><el-button type="primary">添加用户</el-button></el-col></el-row></el-card>
用户数据展示
- 获取所有用户数据
<script>
export default {data() {return {//存放用户数据的数组userList:[],//存放用户总数的数据usertotal:'',//请求用户数据传递的参数queryInfo:{query:'',pagenum:'1',pagesize:'10'}}},created() {//第一时间调用获取用户数据this.getUserList()},methods: {//通过axios获取用户数据async getUserList() {// get 传递参数{params:参数对象{a:1,b:2}}const {data:req} = await this.$http.get("/users",{params:this.queryInfo})// console.log(userList)if(req.meta.status!==200)return this.$message.error("获取用户数据失败!")// 将用户数组存放进data中的userList数组this.userList=req.data.users// 将用户总数存放usertotalthis.usertotal=req.data.total// console.log(this.userList)},},
}
</script>
#### 用户数据渲染
<!-- 用户数据表格 --><el-table :data="userList" border stripe><!-- :data表示获取用户数组 border纵向边框 stripe斑马纹 table --><!-- el-table-column每一模板列数据 label列头部标题 prop列内容数据 --><el-table-column label="用户名" prop="username"></el-table-column><el-table-column label="邮箱" prop="email"></el-table-column><el-table-column label="电话" prop="mobile"></el-table-column><el-table-column label="角色" prop="role_name"></el-table-column><el-table-column label="状态" prop="mg_state"></el-table-column><el-table-column label="操作"></el-table-column></el-table>
表格跟搜索框挨在一起不好看,在全局样式中设置table表格跟头部搜索框一段距离,并且表格字体太大修改小一点
/* tbale表格样式 */
.el-table{/* 设置表格top外边距15px */margin-top: 15px;/* 设置表格内容字体大小 */font-size: 13px;
}
编写表格状态列
我们在状态这一列定义一个作用域插槽
<el-table-column label="状态" prop="mg_state"><!-- 我们创建一个作用域插槽模板来写一个开关按钮,通过slot-scope="scope"来接收当前一行对象数据 --><template slot-scope="scope"><!-- 可以通过scope.row获取当前一行对象,通过.对象中的参数可以获取对应的值 -->{{ scope.row.mg_state }}<!-- 定义一个开关按钮,v-mode的值为true,false,对应开还是关 --><el-switch v-model="scope.row.mg_state"></el-switch></template></el-table-column>
编写操作列
操作列定义了三个按钮,编辑,清除,分配角色,这里我们依然使用作用域插槽
<!-- 为了保持按钮在浏览器不同大小窗口都排列成一行不变形 我们给这行添加一个固定宽度 --><el-table-column label="操作" width="180px"><template slot-scope="values"><!-- 修改按钮 type表示按钮颜色,icon表示按钮图标,size表示按钮大小--><el-button type="primary" icon="el-icon-edit" size="mini"></el-button><!-- 清除按钮 --><el-button type="danger" icon="el-icon-delete" size="mini"></el-button><!-- 分配角色按钮 --><el-button type="warning" icon="el-icon-setting" size="mini"></el-button></template></el-table-column>
我们实现一下鼠标移到按钮上显示按钮功能提示
我们可以给按钮外侧套一层Tooltip 文字提示
<!-- 分配角色按钮 effect表示主体,content提示文字,placement提示方向--><el-tooltip effect="dark" content="分配角色" placement="top"><el-button type="warning" icon="el-icon-setting" size="mini"></el-button></el-tooltip>
数据分页
当我们数据足够多的时候,我们需要设置分页查看
先添加Pagination 分页组件
<!-- 分页区域 --><el-pagination@size-change="handleSizeChange"@current-change="handleCurrentChange":current-page="queryInfo.pagenum":page-sizes="[1, 2, 3, 50]":page-size="queryInfo.pagesize"layout="total, sizes, prev, pager, next, jumper":total="usertotal"><!-- @size-change="handleSizeChange" 表示切换了每页条数的菜单会触发handleSizeChange方法函数 ,在这个函数中可以拿到最新的每页条数--><!-- @current-change="handleCurrentChange" 页码值发生了切换会触发handleCurrentChange方法函数 --><!-- :current-page="currentPage4" 当前显示的是第几页数据 --><!-- :page-sizes="[100, 200, 300, 400]" 下拉菜单显示可以切换显示多少条数据 --><!-- :page-size="100" 当前每页显示多少条数据--><!-- layout 组件布局显示那些功能,比如每页显示多少条数据的下拉菜单 --><!-- :total="400" 数据总数 --></el-pagination>
<script>
export default {data() {return {//存放用户数据的数组userList: [],//存放用户总数的数据usertotal: "",//请求用户数据传递的参数queryInfo: {query: "",// 当前页数pagenum: 1,// 显示多少条数据pagesize: 10,},}},created() {//第一时间调用获取用户数据this.getUserList()},methods: {//通过axios获取用户数据async getUserList() {// get 传递参数{params:参数对象{a:1,b:2}}const { data: req } = await this.$http.get("/users", {params: this.queryInfo,})// console.log(userList)if (req.meta.status !== 200)return this.$message.error("获取用户数据失败!")// 将用户数组存放进data中的userList数组this.userList = req.data.users// 将用户总数存放usertotalthis.usertotal = req.data.total// console.log(this.userList)},//当页面切换显示多少条数据时会触发并接收选择的多少条数据handleSizeChange(newSize){//用户切换每页显示多少条数据,我们修改data中的属性this.queryInfo.pagesize=newSize//设置完每页显示多少条数据后,重新获取一次每页显示多少条的数据this.getUserList()},// 当页码值发生了切换会触发并接收切换的页面值handleCurrentChange(newPage){//设置当前页面this.queryInfo.pagenum=newPage//设置完当前页码后重新获取当前设置完的页面的数据this.getUserList()}},
}
</script>
我们的分页组件需要跟表格设置点距离
在全局样式中添加
/* 分页样式 */
.el-pagination{margin-top: 15px;
}
用户状态修改
我们点击Switch开关按钮发送一条请求修改用户的状态
@change="userStateChanged(values.row)" 代表开关点击后,会触发userStateChanged方法并且携带当前对象
<el-switch v-model="values.row.mg_state" @change="userStateChanged(values.row)"> </el-switch>
//状态按钮点击后执行这个函数方法,来修改用户状态函数async userStateChanged(user_Row){//put请求const {data:req}=await this.$http.put("/users/"+user_Row.id+"/state/"+user_Row.mg_state)// 如果修改失败if(req.meta.status!==200){// 当我们点击按钮后会直接在本地改成false/true,但是数据库没有修改成功,我们将本地的修改为原来的boolenuser_Row.mg_state=!user_Row.mg_state// 发送提示信息return this.$message.error("修改用户状态失败!")}// 如果修改成功,我们发送提示信息this.$message.success("更新用户状态成功!")}
搜索用户
我们给input绑定一个v-model属性值为data中的queryInfo.query,在再buttom上添加一个点击事件,我们点击后调用getuserlist方法即可?
为什么我们不重新写个获取用户的请求而是重复用一个请求呢?
我们的获取用户请求中有三个参数,第一个参数是用户名(可以为空,我们为空代表获取所有用户,不为空代表查询当前输入的用户名)
所有我们可以复用getuserlist方法
<el-input placeholder="请输入内容" v-model="queryInfo.query"><el-button slot="append" icon="el-icon-search" @click="getUserList" ></el-button></el-input>
如果这个时候用户想查询全部用户信息了,又要吧输入框的信息全部清除再次点击一次查询,反而很麻烦
<!--我们给input加一个 clearable 属性代表 输入框可以显示清空按钮,@clear="getUserList"表示 当我们点击清空按钮后执行一个函数
我们清空后会默认执行一个getUserList函数,这个时候我们的v-model="queryInfo.query"的值为空,我们请求getUserList的时候就会显示全部用户信息了-->
<el-input placeholder="请输入内容" v-model="queryInfo.query" clearable @clear="getUserList"><el-button slot="append" icon="el-icon-search" @click="getUserList" ></el-button></el-input>
添加用户
点击添加按钮弹出添加框
<!-- 添加用户对话框 -->
<el-dialog title="提示":visible.sync="addUservisiblesync"width="50%"><!--弹窗主体区域--><span>这是一段信息</span><!--底部按钮组件--><span slot="footer" class="dialog-footer"><!--点击取消将addUservisiblesync修改为false 这样弹窗就会消失--><el-button @click="addUservisiblesync = false">取 消</el-button><el-button type="primary" @click="addUservisiblesync = false">确 定</el-button></span>
</el-dialog>
<!--
title:弹窗标题
:visible.sync:表示是否显示
width:弹窗大小
-->
给弹出框添加表单
<!--弹窗主体区域--><el-form:model="addUserForm":rules="addUserFormrules"ref="ruleAddUserForm"label-width="70px"><!-- :model绑定表单对象,rules校验规则, --><!--label表示input左侧文字 ,prop表示校验规则名称--><el-form-item label="用户名" prop="username"><!--v-model表示与addUserForm对象下的属性绑定--><el-input v-model="addUserForm.username"></el-input></el-form-item><el-form-item label="密码" prop="password"><el-input v-model="addUserForm.password"></el-input></el-form-item><el-form-item label="邮箱" prop="email"><el-input v-model="addUserForm.email"></el-input></el-form-item><el-form-item label="手机号" prop="mobile"><el-input v-model="addUserForm.mobile"></el-input></el-form-item></el-form>
// 添加用户form表单对象addUserForm: {username: "",password: "",email: "",mobile: "",},//用户表单校验规则addUserFormrules: {username: [{ required: true, message: "请输入用户名", trigger: "blur" },{ min: 4, max: 18, message: "长度在 4 到 18 位", trigger: "blur" },],password: [{ required: true, message: "请输入密码", trigger: "blur" },{ min: 4, max: 18, message: "长度在 6 到 18 位", trigger: "blur" },],email: [{ required: true, message: "请输入邮箱", trigger: "blur" },],mobile: [{ required: true, message: "请输入手机号", trigger: "blur" },{ min: 11, max: 11, message: "长度在11位", trigger: "blur" },],},
对表单重置
我们关闭表单后我们刚刚在表单输入的值任然还保存在data中,默认并不会清空。
所有我们要在表单关闭后将我们刚刚输入的信息全部清空重置
这里我们用dialog弹出层中的close属性来定义一个方法,close表示表单关闭后会执行触发
<el-dialog title="提示" :visible.sync="addUservisiblesync" width="50%" @close="addUserClose">
//监听用户对话框关闭事件,添加用户对话关闭后执行,将添加用户的v-model绑定的值重置清空addUserClose(){// 通过refs获取页面定义的ref属性(当前对象)然后执行resetFields方法this.$refs.ruleAddUserForm.resetFields();}
添加用户功能
我们给添加按钮一个点击事件,点击后执行添加请求
<el-button type="primary" @click="addUser">确 定</el-button>
我们先请求用户数据,判断是否添加成功并返回提示,然后关闭弹窗,重新获取所有用户
async addUser(){//添加用户请求const {data:req}=await this.$http.post("/users",this.addUserForm);//添加失败if(req.meta.status!==201) return this.$message.error("添加用户失败!")//添加成功this.$message.success("添加成功!")//关闭弹窗this.addUservisiblesync=false//重新请求加载用户数据this.getUserList()}
修改用户
点击修改即可弹窗修改表单,跟我们添加用户一样添加一个Dialog标签和给:visible.sync添加一个数据双向绑定的值(true,false)
跟添加用户不同的是,我们点击按钮需要携带当前对象属性信息,所以我们在按钮添加一个点击事件执行updateUser方法,方法里面将:visible.sync绑定的值改为true
<!-- 修改用户对话框 --><el-dialog title="修改" :visible.sync="updateUserDialog" width="50%"><span>这是一段信息</span><span slot="footer" class="dialog-footer"><el-button @click="updateUserDialog = false">取 消</el-button><el-button type="primary" @click="updateUserDialog = false">确 定</el-button></span></el-dialog>
data(){retrun:{updateUserDialog=false}}//修改用户updateUser(){//弹窗修改对话框this.updateUserDialog=true}
提交修改数据
//修改用户:请求修改用户返回成功还是失败updateUser() {//做表单验证this.$refs.updateUserRef.validate(async(validate) => {if (!validate) return this.$message.error("请将信息填写正确!")try{const {data:req} = await this.$http.put("/users/" + this.editUser.id, {email: this.editUser.email,mobile: this.editUser.mobile,})if(req.meta.status!==200)return this.$message.error("修改失败")//关闭弹窗this.updateUserDialog=false;//刷新用户列表this.getUserList();//返回提示return this.$message.success("修改成功!")}catch(e){this.$message.error("修改失败或超时!")} })},
用户清除
我们点击清除按钮后,要先弹出一个提示是否确认清除,以免用户误点导致清除。
我们在清除按钮地方添加一个点击事件,将id传递进去
<!-- 清除按钮 --><el-buttontype="danger"icon="el-icon-delete"size="mini"@click="deleteUser(acope.row.id)"></el-button>
我们这里点击后先是弹出一个提示框,用户可以点击确定或者取消
这里用的是MessageBox 弹框,这里跟其他组件引入不同的是
我们要单独引入
MessageBoxVue.prototype.$confirm=MessageBox.confirm
//用户清除点击
async deleteUser(id) {// 参数一:提示信息,参数二,提示标题,参数三:显示按钮,//当我们点击确定按钮或者取消按钮后会返回两个字符串//确定:confirm,取消:cancelconst req =await this.$confirm("此操作将永久删除该用户, 是否继续?", "提示", {confirmButtonText: "确定",cancelButtonText: "取消",type: "warning",//这里点击取消会执行一个错误提示,我们将他捕捉一下}).catch(err=>err)//判断用户是否点击的是确定按钮if(req=="confirm"){//发送清除请求const {data:req}=await this.$http.delete("/users/"+id);//判断是否清除成功if(req.meta.status!=200)return this.$message.error("清除失败!")//刷新用户列表this.getUserList();//界面提示this.$message.success("清除成功!")}},
分配角色
添加点击事件
<!-- 分配角色按钮 effect表示主体,content提示文字,placement提示方向--><el-tooltip effect="dark" content="分配角色" placement="top"><el-buttontype="warning"icon="el-icon-setting"size="mini"@click="roleUser(acope.row)"></el-button></el-tooltip>
// 获取角色列表async roleUser(row) {this.UserInfo = rowconst { data: req } = await this.$http.get("/roles")//判断是否成功if (req.meta.status != 200)return this.$message.error("获取权限失败!")this.rolesList = req.datathis.rolesdialog = true},//设置角色async setRole() {const { data: req } = await this.$http.put(`/users/${this.UserInfo.id}/role`,{rid: this.rolesValue})//判断是否成功if (req.meta.status != 200)return this.$message.error("分配失败!")this.$message.success("分配成功!")this.rolesdialog = falsethis.getUserList()this.rolesValue=''},
用户列表完整代码
<template><div><!-- 面包屑导航 --><el-breadcrumb separator-class="el-icon-arrow-right"><el-breadcrumb-item :to="{ path: '/Home' }">首页</el-breadcrumb-item><el-breadcrumb-item>用户管理</el-breadcrumb-item><el-breadcrumb-item>用户列表</el-breadcrumb-item></el-breadcrumb><!-- 卡片试图区 --><el-card class="box-card"><!-- 搜索与添加 --><el-row :gutter="20"><!-- :gutter="20"设置两栏间距 设置这一栏大小 --><el-col :span="8"><!-- 搜索与添加区域 --><el-inputplaceholder="请输入内容"v-model="queryInfo.query"clearable@clear="getUserList"><el-buttonslot="append"icon="el-icon-search"@click="getUserList"></el-button></el-input></el-col><el-col :span="4"><!-- 按钮 --><el-button type="primary" @click="addUservisiblesync = true">添加用户</el-button></el-col></el-row><!-- 用户数据表格 --><el-table :data="userList" border stripe><!-- :data表示获取用户数组 border纵向边框 stripe斑马纹 table --><!-- el-table-column每一列数据 label列头部标题 prop列内容数据 --><el-table-column type="index" label="#"></el-table-column><el-table-column label="用户名" prop="username"></el-table-column><el-table-column label="邮箱" prop="email"></el-table-column><el-table-column label="电话" prop="mobile"></el-table-column><el-table-column label="角色" prop="role_name"></el-table-column><el-table-column label="状态"><!-- 我们创建一个作用域插槽模板来写一个开关按钮 通过slot-scope="scope"来接收当前一行对象数据--><template slot-scope="values"><!-- 可以通过scope.row获取当前一行对象,通过.对象中的参数可以获取对应的值 --><!-- {{ values.row.mg_state }} --><!-- 定义一个开关按钮,v-mode的值为true,false,对应开还是关 --><el-switchv-model="values.row.mg_state"@change="userStateChanged(values.row)"></el-switch></template></el-table-column><el-table-column label="操作" width="180px"><template slot-scope="acope"><!-- 修改按钮 --><el-buttontype="primary"icon="el-icon-edit"size="mini"@click="queryUserByid(acope.row.id)"></el-button><!-- 清除按钮 --><el-buttontype="danger"icon="el-icon-delete"size="mini"@click="deleteUser(acope.row.id)"></el-button><!-- 分配角色按钮 effect表示主体,content提示文字,placement提示方向--><el-tooltip effect="dark" content="分配角色" placement="top"><el-buttontype="warning"icon="el-icon-setting"size="mini"@click="roleUser(acope.row)"></el-button></el-tooltip></template></el-table-column></el-table><!-- 分页区域 --><el-pagination@size-change="handleSizeChange"@current-change="handleCurrentChange":current-page="queryInfo.pagenum":page-sizes="[10, 20, 50, 100]":page-size="queryInfo.pagesize"layout="total, sizes, prev, pager, next, jumper":total="usertotal"><!-- @size-change="handleSizeChange" 表示切换了每页条数的菜单会触发handleSizeChange方法函数 ,在这个函数中可以拿到最新的每页条数--><!-- @current-change="handleCurrentChange" 页码值发生了切换会触发handleCurrentChange方法函数 --><!-- :current-page="currentPage4" 当前显示的是第几页数据 --><!-- :page-sizes="[100, 200, 300, 400]" 下拉菜单显示可以切换显示多少条数据 --><!-- :page-size="100" 当前每页显示多少条数据--><!-- layout 组件布局显示那些功能,比如每页显示多少条数据的下拉菜单 --><!-- :total="400" 数据总数 --></el-pagination></el-card><!-- 添加用户对话框 --><el-dialogtitle="提示":visible.sync="addUservisiblesync"width="50%"@close="addUserClose"><!--title:弹窗标题:visible.sync:表示是否显示width:弹窗大小--><!--弹窗主体区域--><el-form:model="addUserForm":rules="addUserFormrules"ref="ruleAddUserForm"label-width="70px"><!-- :model绑定表单对象,rules校验规则,ref表示当前表单对象 --><el-form-item label="用户名" prop="username"><el-input v-model="addUserForm.username"></el-input></el-form-item><el-form-item label="密码" prop="password"><el-input v-model="addUserForm.password"></el-input></el-form-item><el-form-item label="邮箱" prop="email"><el-input v-model="addUserForm.email"></el-input></el-form-item><el-form-item label="手机号" prop="mobile"><el-input v-model="addUserForm.mobile"></el-input></el-form-item></el-form><!--底部按钮组件--><span slot="footer" class="dialog-footer"><!--点击取消将addUservisiblesync修改为false 这样弹窗就会消失--><el-button @click="addUservisiblesync = false">取 消</el-button><el-button type="primary" @click="addUser">确 定</el-button></span></el-dialog><!-- 修改用户对话框 --><el-dialogtitle="修改":visible.sync="updateUserDialog"width="50%"@close="updateUserClose"><!-- 修改用户表单 --><el-formref="updateUserRef":model="editUser":rules="addUserFormrules"label-width="80px"><el-form-item label="用户名"><el-input v-model="editUser.username" :disabled="true"></el-input></el-form-item><el-form-item label="邮箱" prop="email"><el-input v-model="editUser.email"></el-input></el-form-item><el-form-item label="手机号" prop="mobile"><el-input v-model="editUser.mobile"></el-input></el-form-item></el-form><span slot="footer" class="dialog-footer"><el-button @click="updateUserDialog = false">取 消</el-button><el-button type="primary" @click="updateUser">确 定</el-button></span></el-dialog><!-- 分配角色 --><el-dialog title="分配角色" :visible.sync="rolesdialog" width="50%"><el-form label-width="80px"><el-form-item label="用户名"><el-input :disabled="true" v-model="UserInfo.username"></el-input></el-form-item><el-form-item label="用户名"><el-input :disabled="true" v-model="UserInfo.role_name"></el-input></el-form-item><el-form-item label="切换角色"><el-select v-model="rolesValue" placeholder="请选择"><el-optionv-for="(item, index) in rolesList":key="index":label="item.roleName":value="item.id"></el-option></el-select></el-form-item></el-form><span slot="footer" class="dialog-footer"><el-button @click="rolesdialog = false">取 消</el-button><el-button type="primary" @click="setRole">确 定</el-button></span></el-dialog></div>
</template>
<script>
import { MessageBox } from "element-ui"
export default {data() {return {rolesList: [],rolesValue: "",//存放用户数据的数组userList: [],//存放用户总数的数据usertotal: 0,//请求用户数据传递的参数queryInfo: {query: "",// 当前页数pagenum: 1,// 显示多少条数据pagesize: 10,},//添加用户弹窗addUservisiblesync: false,//修改用户弹窗updateUserDialog: false,//用户信息UserInfo: {},// 添加用户form表单对象addUserForm: {username: "",password: "",email: "",mobile: "",},//修改用户,查询到的用户信息保存对象editUser: {},//分配角色弹窗rolesdialog: false,//用户表单校验规则addUserFormrules: {username: [{ required: true, message: "请输入用户名", trigger: "blur" },{ min: 4, max: 18, message: "长度在 4 到 18 位", trigger: "blur" },],password: [{ required: true, message: "请输入密码", trigger: "blur" },{ min: 4, max: 18, message: "长度在 6 到 18 位", trigger: "blur" },],email: [{ required: true, message: "请输入邮箱地址", trigger: "blur" },{type: "email",message: "请输入正确的邮箱地址",trigger: ["blur", "change"],},],mobile: [{ required: true, message: "请输入手机号", trigger: "blur" },{ min: 11, max: 11, message: "长度在11位", trigger: "blur" },],},}},created() {//第一时间调用获取用户数据this.getUserList()},methods: {//通过axios获取用户数据async getUserList() {// get 传递参数{params:参数对象{a:1,b:2}}try {const { data: req } = await this.$http.get("/users", {params: this.queryInfo,})// console.log(userList)if (req.meta.status !== 200)return this.$message.error("获取用户数据失败!")// 将用户数组存放进data中的userList数组this.userList = req.data.users// 将用户总数存放usertotalthis.usertotal = req.data.total// console.log(this.userList)} catch (e) {return this.$message.error("获取用户数据失败!")}},//当页面切换显示多少条数据时会触发并接收选择的多少条数据handleSizeChange(newSize) {//用户切换每页显示多少条数据,我们修改data中的属性this.queryInfo.pagesize = newSize//设置完每页显示多少条数据后,重新获取一次每页显示多少条的数据this.getUserList()},// 当页码值发生了切换会触发并接收切换的页面值handleCurrentChange(newPage) {//设置当前页面this.queryInfo.pagenum = newPage//设置完当前页码后重新获取当前设置完的页面的数据this.getUserList()},//状态按钮点击后执行这个函数方法,来修改用户状态函数async userStateChanged(user_Row) {//put请求const { data: req } = await this.$http.put("/users/" + user_Row.id + "/state/" + user_Row.mg_state)// 如果修改失败if (req.meta.status !== 200) {// 当我们点击按钮后会直接在本地改成false/true,但是数据库没有修改成功,我们将本地的修改为原来的boolenuser_Row.mg_state = !user_Row.mg_state// 发送提示信息return this.$message.error("修改用户状态失败!")}// 如果修改成功,我们发送提示信息this.$message.success("更新用户状态成功!")},//监听用户对话框关闭事件,添加用户对话关闭后执行,将添加用户的v-model绑定的值重置清空addUserClose() {// 通过refs获取页面定义的ref属性(当前对象)然后执行resetFields方法this.$refs.ruleAddUserForm.resetFields()},async addUser() {//添加用户请求const { data: req } = await this.$http.post("/users", this.addUserForm)//添加失败if (req.meta.status !== 201) return this.$message.error("添加用户失败!")//添加成功this.$message.success("添加成功!")//关闭弹窗this.addUservisiblesync = false//重新请求加载用户数据this.getUserList()},//通过id查询用户信息async queryUserByid(id) {try {const { data: req } = await this.$http.get("/users/" + id)//弹窗修改对话框if (req.meta.status !== 200)return this.$message.error("获取用户数据失败!")this.editUser = req.dataconsole.log(this.editUser)this.updateUserDialog = true} catch (e) {return this.$message.error("获取用户数据超时!")}},//监听修改用户的弹窗关闭后执行的方法updateUserClose() {//通过this.$ref获取当前表单updateUserRef然后执行resetFields方法this.$refs.updateUserRef.resetFields()},//修改用户:请求修改用户返回成功还是失败updateUser() {//做表单验证this.$refs.updateUserRef.validate(async (validate) => {if (!validate) return this.$message.error("请将信息填写正确!")try {const { data: req } = await this.$http.put("/users/" + this.editUser.id,{email: this.editUser.email,mobile: this.editUser.mobile,})if (req.meta.status !== 200) return this.$message.error("修改失败")//关闭弹窗this.updateUserDialog = false//刷新用户列表this.getUserList()//返回提示return this.$message.success("修改成功!")} catch (e) {this.$message.error("修改失败或超时!")}})},//用户清除点击async deleteUser(id) {// 参数一:提示信息,参数二,提示标题,参数三:显示按钮,//当我们点击确定按钮或者取消按钮后会返回两个字符串//确定:confirm,取消:cancelconst req = await this.$confirm("此操作将永久删除该用户, 是否继续?","提示",{confirmButtonText: "确定",cancelButtonText: "取消",type: "warning",//这里点击取消会执行一个错误提示,我们将他捕捉一下}).catch((err) => err)//判断用户是否点击的是确定按钮if (req == "confirm") {//发送清除请求const { data: req } = await this.$http.delete("/users/" + id)//判断是否清除成功if (req.meta.status != 200) return this.$message.error("清除失败!")//刷新用户列表this.getUserList()//界面提示this.$message.success("清除成功!")}},// 获取角色列表async roleUser(row) {//将传递的row存放在data数据中this.UserInfo = row//请求获取角色列表const { data: req } = await this.$http.get("/roles")//判断是否成功if (req.meta.status != 200)//判断失败return this.$message.error("获取权限失败!")//将角色列表存放在data中this.rolesList = req.data//将弹窗关闭this.rolesdialog = true},//设置角色async setRole() {//请求设置角色const { data: req } = await this.$http.put(`/users/${this.UserInfo.id}/role`,{rid: this.rolesValue})//判断是否成功if (req.meta.status != 200)return this.$message.error("分配失败!")//提示信息this.$message.success("分配成功!")//关闭弹窗this.rolesdialog = false//刷新用户数据this.getUserList()//将默认选中的value清空以防下次覆盖this.rolesValue=''},},
}
</script><style scoped></style>
权限管理
权限列表
注册router路由
{path: "/rights",name: "Righs",component: () => import("../components/power/Rights.vue"),},
<template><div><!-- 面包屑导航 --><el-breadcrumb separator-class="el-icon-arrow-right"><el-breadcrumb-item :to="{ path: '/Home' }">首页</el-breadcrumb-item><el-breadcrumb-item>权限管理</el-breadcrumb-item><el-breadcrumb-item>权限列表</el-breadcrumb-item></el-breadcrumb><!-- 卡片视图 --><el-card><!-- table表格 :data表示对应的数据源 --><el-table :data="rightsList"><el-table-column label="#" type="index"></el-table-column><!-- label表格 label表示头部 prop表示数据源属性--><el-table-column label="权限名称" prop="authName"></el-table-column><el-table-column label="路径" prop="path"></el-table-column><el-table-column label="权限等级"><template slot-scope="scope"><el-tag v-if="scope.row.level == 0">一级</el-tag><el-tag v-else-if="scope.row.level == 1" type="success">二级</el-tag><el-tag v-else type="danger">三级</el-tag></template></el-table-column></el-table></el-card></div>
</template>
<script>
export default {data() {return {//权限列表rightsList: [],}},created() {//获取权限列表this.getrightsList()},methods: {//请求权限信息async getrightsList() {const { data: req } = await this.$http.get("/rights/list")if (req.meta.status !== 200) return this.$message.error("获取数据失败!")this.rightsList = req.data},},
}
</script>
<style scoped></style>
这里运用了Tag标签,element.js引入
Tag
Vue.use(Tag)
角色列表
获取角色列表
<template><div><!-- 面包屑导航 --><el-breadcrumb separator-class="el-icon-arrow-right"><el-breadcrumb-item :to="{ path: '/Home' }">首页</el-breadcrumb-item><el-breadcrumb-item>权限管理</el-breadcrumb-item><el-breadcrumb-item>角色列表</el-breadcrumb-item></el-breadcrumb><!-- 卡片视图 --><el-card><!-- 添加角色按钮 --><el-row><el-button type="primary">添加角色</el-button></el-row><!-- 角色列表视图 --><el-table :data="roleList" border stripe><!-- 索引列 --><el-table-column label="#" type="index"></el-table-column><el-table-column label="角色名称" prop="roleName"></el-table-column><el-table-column label="角色描述" prop="roleDesc"></el-table-column><el-table-column label="操作" width="300px"><template slot-scope=""><el-button type="primary" icon="el-icon-edit" size="mini">编辑</el-button><el-button type="danger" icon="el-icon-delete" size="mini">清除</el-button><el-button type="warning" icon="el-icon-setting" size="mini">分配权限</el-button></template></el-table-column></el-table></el-card></div>
</template>
<script>
export default {data() {return {//所以角色列表数据roleList: [],}},created() {this.getroleList()},methods: {//请求全部角色列表信息async getroleList() {const { data: req } = await this.$http.get("/roles")if(req.meta.status!==200)return this.$message.error("获取数据失败!")this.roleList=req.data},},
}
</script>
<style scoped></style>
实现展开列
我们这里有三级权限,有多个一级权限,一级权限对应多个二级权限,二级权限对应多个三级权限
所以这里我们使用for循环嵌套三层
每循环一个一级权限,都会将这个一级权限包含的二级三级全部循环出来
我们直接渲染即可
<el-row:class="[item1 == 0 ? '' : 'bordertop','borderbottom','vcenter',]"v-for="(item1, index) in scope.row.children":key="index"><!-- 占位符,将所有表格将右移动一格 可忽略--><el-col :span="1"></el-col><!-- 渲染一级权限 --><el-col :span="5"><el-tagclosable@close="removeRightById(scope.row, item1.id)">{{ item1.authName }}</el-tag><i class="el-icon-caret-right"></i></el-col><!-- 通过一级权限下children,的渲染二级权限 --><el-col :span="18"><!-- 通过for循环嵌套 --><el-rowv-for="(item2, index) in item1.children":key="index":class="[item2 == 0 ? '' : 'bordertop', 'vcenter']"><!-- 渲染二级权限 --><el-col :span="6"><el-tagclosable@close="removeRightById(scope.row, item2.id)"type="success">{{ item2.authName }}</el-tag><i class="el-icon-caret-right"></i></el-col><!-- 渲染三级权限 --><el-col :span="18"><el-tagtype="warning"closable@close="removeRightById(scope.row, item3.id)"v-for="(item3, index) in item2.children":key="index">{{ item3.authName }}</el-tag></el-col></el-row></el-col></el-row>
完整代码
<template><div><!-- 面包屑导航 --><el-breadcrumb separator-class="el-icon-arrow-right"><el-breadcrumb-item :to="{ path: '/Home' }">首页</el-breadcrumb-item><el-breadcrumb-item>权限管理</el-breadcrumb-item><el-breadcrumb-item>角色列表</el-breadcrumb-item></el-breadcrumb><!-- 卡片视图 --><el-card><!-- 添加角色按钮 --><el-row><el-button type="primary">添加角色</el-button></el-row><!-- 角色列表视图 --><el-table :data="roleList" border stripe><!-- 展开列 --><el-table-column type="expand"><template slot-scope="scope"><!-- 栅格系统 将页面切割24份 --><el-row:class="[item1 == 0 ? '' : 'bordertop','borderbottom','vcenter',]"v-for="(item1, index) in scope.row.children":key="index"><el-col :span="1"></el-col><!-- 渲染一级权限 --><el-col :span="5"><el-tagclosable@close="removeRightById(scope.row, item1.id)">{{ item1.authName }}</el-tag><i class="el-icon-caret-right"></i></el-col><!-- 渲染二级权限 --><el-col :span="18"><!-- 通过for循环嵌套 --><el-rowv-for="(item2, index) in item1.children":key="index":class="[item2 == 0 ? '' : 'bordertop', 'vcenter']"><!-- 渲染二级权限 --><el-col :span="6"><el-tagclosable@close="removeRightById(scope.row, item2.id)"type="success">{{ item2.authName }}</el-tag><i class="el-icon-caret-right"></i></el-col><!-- 渲染三级权限 --><el-col :span="18"><el-tagtype="warning"closable@close="removeRightById(scope.row, item3.id)"v-for="(item3, index) in item2.children":key="index">{{ item3.authName }}</el-tag></el-col></el-row></el-col></el-row></template></el-table-column><!-- 索引列 --><el-table-column label="#" type="index"></el-table-column><el-table-column label="角色名称" prop="roleName"></el-table-column><el-table-column label="角色描述" prop="roleDesc"></el-table-column><el-table-column label="操作" width="300px"><template slot-scope=""><el-button type="primary" icon="el-icon-edit" size="mini">编辑</el-button><el-button type="danger" icon="el-icon-delete" size="mini">清除</el-button><el-button type="warning" icon="el-icon-setting" size="mini">分配权限</el-button></template></el-table-column></el-table></el-card></div>
</template>
<script>
export default {data() {return {//所以角色列表数据roleList: [],}},created() {this.getroleList()},methods: {//获取角色列表async getroleList() {const { data: req } = await this.$http.get("/roles")if (req.meta.status !== 200) return this.$message.error("获取数据失败!")this.roleList = req.data},//根据id清除对应的权限async removeRightById(role, rightsid) {const res = await this.$confirm("此操作将永久删除该用户, 是否继续?","提示",{confirmButtonText: "确定",cancelButtonText: "取消",type: "warning",//这里点击取消会执行一个错误提示,我们将他捕捉一下}).catch((err) => err)//判断用户是否点击的是确定按钮if (res == "confirm") {//发送清除请求const { data: req } = await this.$http.delete(`roles/${role.id}/rights/${rightsid}`)//判断是否清除成功if (req.meta.status != 200) return this.$message.error("清除失败!")//刷新用户列表role.children = req.data//界面提示this.$message.success("清除成功!")}},},
}
</script>
<style scoped>
.el-tag {margin: 7px;
}
.bordertop {border-top: 1px solid #eee;
}
.borderbottom {border-bottom: 1px solid #eee;
}
.vcenter {display: flex;align-items: center;
}
</style>
角色分配权限
添加点击事件
<el-buttontype="warning"icon="el-icon-setting"size="mini"@click="showSetRightDialog(scope.row)">分配权限</el-button>
//分配权限加载树形控件async showSetRightDialog(row) {//将角色id赋值给data中的roleId,方便点击其他函数调用this.roleId=row.id//先获取当前所有权限在弹出对话框const { data: req } = await this.$http.get("rights/tree")if (req.meta.status !== 200) return this.$message.error("获取失败!")//将获取到的权限保存进权限列表this.rightsList = req.data//调用递归函数获取第三层的权限idthis.getLeafkeys(row, this.defkeys)//打开弹出框this.dialogVisible = true},//通过递归获取当前下所有的三级权限idgetLeafkeys(node, arr) {//如果当前data数据不包含children属性,则是三级节点if (!node.children) {return arr.push(node.id)}//如果当前右children属性表示不是三级权限id继续调用本方法继续循环node.children.forEach((item) => this.getLeafkeys(item, arr))},//弹出框关闭后将树杈属性清空,否者再次会打开其他的会覆盖属性Dialogclose() {//将权限节点id数组清空this.defkeys = []},// 为角色分配权限async allotRights() {//获取当前树杈全部选中的idconst kyes = [//获取一级和二级的权限id...this.$refs.treeRef.getCheckedKeys(),//获取三级的权限id...this.$refs.treeRef.getHalfCheckedKeys()]//将树杈选中的权限id解析成字符串以逗号(,)分割 例如1,2,3,4,5const idStr = kyes.join(",")//发送修改请求 this.roleId 从data中取的,从按钮中没有办法取,所以我们定义一个属性,在用户点击分配角色时加载树形控件(showSetRightDialog)时将角色id赋值一下const { data: req } = await this.$http.post(`roles/${this.roleId}/rights`,{rids:idStr})if (req.meta.status !== 200) return this.$message.error("获取失败!")this.$message.success("分配成功!")this.getroleList()this.dialogVisible=false},},
完整代码
角色列表代码
<template><div><!-- 面包屑导航 --><el-breadcrumb separator-class="el-icon-arrow-right"><el-breadcrumb-item :to="{ path: '/Home' }">首页</el-breadcrumb-item><el-breadcrumb-item>权限管理</el-breadcrumb-item><el-breadcrumb-item>角色列表</el-breadcrumb-item></el-breadcrumb><!-- 卡片视图 --><el-card><!-- 添加角色按钮 --><el-row><el-button type="primary">添加角色</el-button></el-row><!-- 角色列表视图 --><el-table :data="roleList" border stripe><!-- 展开列 --><el-table-column type="expand"><template slot-scope="scope"><!-- 栅格系统 将页面切割24份 --><el-row:class="[item1 == 0 ? '' : 'bordertop','borderbottom','vcenter',]"v-for="(item1, index) in scope.row.children":key="index"><el-col :span="1"></el-col><!-- 渲染一级权限 --><el-col :span="5"><el-tagclosable@close="removeRightById(scope.row, item1.id)">{{ item1.authName }}</el-tag><i class="el-icon-caret-right"></i></el-col><!-- 渲染二级权限 --><el-col :span="18"><!-- 通过for循环嵌套 --><el-rowv-for="(item2, index) in item1.children":key="index":class="[item2 == 0 ? '' : 'bordertop', 'vcenter']"><!-- 渲染二级权限 --><el-col :span="6"><el-tagclosable@close="removeRightById(scope.row, item2.id)"type="success">{{ item2.authName }}</el-tag><i class="el-icon-caret-right"></i></el-col><!-- 渲染三级权限 --><el-col :span="18"><el-tagtype="warning"closable@close="removeRightById(scope.row, item3.id)"v-for="(item3, index) in item2.children":key="index">{{ item3.authName }}</el-tag></el-col></el-row></el-col></el-row></template></el-table-column><!-- 索引列 --><el-table-column label="#" type="index"></el-table-column><el-table-column label="角色名称" prop="roleName"></el-table-column><el-table-column label="角色描述" prop="roleDesc"></el-table-column><el-table-column label="操作" width="300px"><template slot-scope="scope"><el-button type="primary" icon="el-icon-edit" size="mini">编辑</el-button><el-button type="danger" icon="el-icon-delete" size="mini">清除</el-button><el-buttontype="warning"icon="el-icon-setting"size="mini"@click="showSetRightDialog(scope.row)">分配权限</el-button></template></el-table-column></el-table></el-card><!-- 弹出对话框 --><el-dialogtitle="提示":visible.sync="dialogVisible"width="50%"@close="Dialogclose()"><!-- 树形控件 --><el-treeshow-checkbox:data="rightsList"ref="treeRef":props="defaultProps"default-expand-allnode-key="id":default-checked-keys="defkeys"></el-tree><span slot="footer" class="dialog-footer"><el-button @click="dialogVisible = false">取 消</el-button><el-button type="primary" @click="allotRights()">确 定</el-button></span></el-dialog></div>
</template>
<script>
export default {data() {return {//弹出对话框dialogVisible: false,//所以角色列表数据roleList: [],//所有权限列表数据rightsList: [],defaultProps: {children: "children",label: "authName",},// 默认选中的权限节点Id值数组defkeys: [],//当前角色IDroleId:''}},created() {this.getroleList()},methods: {//获取角色列表async getroleList() {const { data: req } = await this.$http.get("/roles")if (req.meta.status !== 200) return this.$message.error("获取数据失败!")this.roleList = req.data},//根据id清除对应的权限async removeRightById(role, rightsid) {const res = await this.$confirm("此操作将永久删除该用户, 是否继续?","提示",{confirmButtonText: "确定",cancelButtonText: "取消",type: "warning",//这里点击取消会执行一个错误提示,我们将他捕捉一下}).catch((err) => err)//判断用户是否点击的是确定按钮if (res == "confirm") {//发送清除请求const { data: req } = await this.$http.delete(`roles/${role.id}/rights/${rightsid}`)//判断是否清除成功if (req.meta.status != 200) return this.$message.error("清除失败!")//刷新用户列表role.children = req.data//界面提示this.$message.success("清除成功!")}},//分配权限加载树形控件async showSetRightDialog(row) {//将角色id赋值给data中的roleId,方便点击其他函数调用this.roleId=row.id//先获取当前所有权限在弹出对话框const { data: req } = await this.$http.get("rights/tree")if (req.meta.status !== 200) return this.$message.error("获取失败!")//将获取到的权限保存进权限列表this.rightsList = req.data//调用递归函数获取第三层的权限idthis.getLeafkeys(row, this.defkeys)//打开弹出框this.dialogVisible = true},//通过递归获取当前下所有的三级权限idgetLeafkeys(node, arr) {//如果当前data数据不包含children属性,则是三级节点if (!node.children) {return arr.push(node.id)}//如果当前右children属性表示不是三级权限id继续调用本方法继续循环node.children.forEach((item) => this.getLeafkeys(item, arr))},//弹出框关闭后将树杈属性清空,否者再次会打开其他的会覆盖属性Dialogclose() {//将权限节点id数组清空this.defkeys = []},// 为角色分配权限async allotRights() {//获取当前树杈全部选中的idconst kyes = [//获取一级和二级的权限id...this.$refs.treeRef.getCheckedKeys(),//获取三级的权限id...this.$refs.treeRef.getHalfCheckedKeys()]//将树杈选中的权限id解析成字符串以逗号(,)分割 例如1,2,3,4,5const idStr = kyes.join(",")//发送修改请求 this.roleId 从data中取的,从按钮中没有办法取,所以我们定义一个属性,在用户点击分配角色时加载树形控件(showSetRightDialog)时将角色id赋值一下const { data: req } = await this.$http.post(`roles/${this.roleId}/rights`,{rids:idStr})if (req.meta.status !== 200) return this.$message.error("获取失败!")this.$message.success("分配成功!")this.getroleList()this.dialogVisible=false},},
}
</script>
<style scoped>
.el-tag {margin: 7px;
}
.bordertop {border-top: 1px solid #eee;
}
.borderbottom {border-bottom: 1px solid #eee;
}
.vcenter {display: flex;align-items: center;
}
</style>
权限列表
<template><div><!-- 面包屑导航 --><el-breadcrumb separator-class="el-icon-arrow-right">
Vue框架教程-从入门到项目实战相关推荐
- 视频教程-最新完整VUE前端教程从入门到精通,纯干货企业级项目实战-Vue
最新完整VUE前端教程从入门到精通,纯干货企业级项目实战 10年以上开发经验,曾经是八维教育实训主任,千峰教育高级HTML5前端讲师,尚品中国创始人.现任程序思维创始人.曾和大厂.国企等大型企业合作开 ...
- 视频教程-20年Nodejs教程零基础入门到项目实战前端视频教程-Node.js
20年Nodejs教程零基础入门到项目实战前端视频教程 7年的开发架构经验,曾就职于国内一线互联网公司,开发工程师,现在是某创业公司技术负责人, 擅长语言有node/java/python,专注于服务 ...
- 前端《Vue.js从入门到项目实战》PDF课件+《微信小程序实战入门第2版》PDF代码调试
JS进行开发,正如一切的编程语言都立足于电元信号的正负极,即01码,可为什么软件都不采用二进制编码来 进行开发呢?这里面牵扯到一个成本的问题,这正是影响项目领导者进行决策的关键因素.Vue项目与原生J ...
- 2018年最新Vue从基础入门到项目实战视频教程网盘学习地址
2018年最新Vue从基础入门到项目实战视频教程网盘学习地址: https://pan.baidu.com/s/15D6GiHnSgA5Eo0n9G5Ws1A 若网盘地址失效,可访问此地址(下单有网盘 ...
- 2022 最新 Android 基础教程,从开发入门到项目实战【b站动脑学院】学习笔记——第六章:数据存储
第 6 章 数据存储 本章介绍Android 4种存储方式的用法,包括共享参数SharedPreferences.数据库SQLite.存储卡文 件.App的全局内存,另外介绍Android重要组件-应 ...
- 2022 最新 Android 基础教程,从开发入门到项目实战【b站动脑学院】学习笔记——第三章:简单控件
第 3 章 简单控件 本章介绍了App开发常见的几类简单控件的用法,主要包括:显示文字的文本视图.容纳视图的常用布局.响应点击的按钮控件.显示图片的图像视图等.然后结合本章所学的知识,演示了一个实战项 ...
- 2022 最新 Android 基础教程,从开发入门到项目实战【b站动脑学院】学习笔记——第五章:中级控件
第 5 章 中级控件 本章介绍App开发常见的几类中级控件的用法,主要包括:如何定制几种简单的图形.如何使用几种选择按钮.如何高效地输入文本.如何利用对话框获取交互信息等,然后结合本章所学的知识,演示 ...
- 视频教程-Vue-cli3.x从入门到项目实战视频课程-Vue
Vue-cli3.x从入门到项目实战视频课程 北京八维研修学院技术工程师,5年大型项目实战开发经验,3年授课经验. 孟宪杰 ¥68.00 立即订阅 扫码下载「CSDN程序员学院APP」,1000+技术 ...
- 5G 时代的 Android App 开发入门与项目实战
随着移动互联网的持续发展,Android系统从智能手机逐步拓展到平板电脑.智能电视.车载大屏.智能家居.智能手表等诸多设备,Android开发依然是前景可期的IT岗位. 当然,整个社会正在迈向5G时代 ...
最新文章
- ae编程语言as_AE开发 入门教程
- php依次替换文本字符串中的图片src地址
- [译]yield关键字都做了什么?
- 手脱ASProtect v1.23 RC1(无Stolen Code)
- 微信小程序时间标签与范围联动设计实现
- objective-c(初始化)
- JVM 类型的生命周期学习
- 图片测量尺寸软件_3D扫描之工件测量检测
- 可以访问本地mysql服务器的命令是_在用户访问本地MySQL服务器时,访问命令可以省略“–h localhost”。...
- Android使用百度翻译api
- jQuery 性能优化指南(2)
- 遮罩层 fixed 在 ie 里无法显示
- 软件测试之 app测试的工具汇总
- Cloud Computing HCIA-③华为企业级虚拟化解决方案
- C++描述 LeetCode 480. 滑动窗口中位数
- 累次积分怎么计算_【高等数学】二重积分化累次积分方法
- 1,	定义一个基类BaseClass,从它派生出类DerivedClass。BaseClass里有成员函数fn1(),fn2(),DerivedClass也有成员函数fn1(),fn2()。在主函数中
- 7月18日云栖精选夜读丨蚂蚁金服的“野心”:要做新一代世界级金融科技供应商...
- Why the MonthCalendar.MinDate is 01/01/1753?
- 世 界 上 最 经 典 的 25 句 话 (带卡通图说明)