在Vue组件中,data函数返回的是一个对象,该对象中包含所有与该组件相关的数据。在这段代码中,data函数返回一个对象,它包含了该组件所需的所有数据,包括currentRow、roleList、roleFormVisible、roleAuthVisible、role、roleRules等等这些数据是组件的重要部分,它们描述了组件的状态和属性,并且能够驱动组件的UI交互行为。提前声明这些数据而不是在需要它们时动态声明,允许Vue在组件渲染和更新时即时访问和修改这些数据,以保持UI状态和行为的一致性。
此外,由于这些数据是响应式的,它们的变化会自动触发Vue的更新机制,导致组件渲染以反映最新的数据状态。所以在组件中提前声明并初始这些数据很重要,可以使代码更容易维护和理解,避免了无意修改应用程序状态的风险。
在后端服务器中的router的index.js中进行设置
接收前端地址/manage/role/add发出的post请求并处理
// 添加角色
router.post("/manage/role/add",(req,res)=>{
const {name} = req.body
RoleModel.create({name}).then(role=>{
res.send({status:0,data:role})
}).catch(error=>{
console.log("添加角色异常",error);
res.send({status:1,msg:'添加角色异常,请重试'})
})
})
RoleModel.js中定义了用户信息规则,故需使用RoleModel.create().then创建
同时将name
保存到数据库中
RoleModel.create
方法是在RoleModel.js
中定义的,并通过mongoose.model
方法创建了一个名为roles
的模型。在RoleModel.js
中,定义了角色的数据结构,包括name
、auth_name
、auth_time
、create_time
和menus
等字段,并指定了各个字段的类型、验证规则和默认值。当调用RoleModel.create({name})
时,会使用name
参数创建一个新的角色实例并保存到数据库中。
const mongoose = require('mongoose')
const roleSchema = new mongoose.Schema({
name:{type:String,required:true},
auth_name:String,
auth_time:Number,
create_time:{type:Number,default:Date.now},
menus:Array
})
const RoleModel = mongoose.model('roles',roleSchema)
module.exports = RoleModel
设置完可以在postman中发送post请求进行测试
// 添加角色
addRole(name){
return request({
url:'/manage/role/add',
method:'post',
data:{
name
}
})
},
(1)前端代码中的addRole
方法使用了request
函数发送POST请求到/manage/role/add
接口,请求体中包含了name
参数。
(2)后端代码中的路由/manage/role/add(添加角色接口)
处理了该POST请求,并从请求体中获取name
参数,然后使用RoleModel.create
方法将name
保存到数据库中。
:formatter
是 Element UI 的功能。在 Element UI 的
组件中,:formatter
是一个属性,用于指定对表格数据进行格式化的函数。通过指定 :formatter
属性,你可以自定义一个函数来格式化表格中的数据。在这个例子中,resetDate
可能是一个在 Vue 组件中定义的方法,用于对日期进行重置和格式化操作。在渲染表格时,Element UI 会调用 resetDate
方法,并将当前行的数据作为参数传入,然后将返回的格式化后的数据显示在表格中。这样可以方便地在表格中显示经过格式化处理的数据。
注意:使用formateDate格式化时间功能时要引入响应组件
methods中的格式化方法:
// 格式化日期
resetDate(row, column, cellValue, index) {
return formateDate(cellValue);
},
// 添加角色
addData(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
roleApi.addRole(this.role.name).then((response) => {
const resp = response.data;
if (resp.status == 0) {
this.roleFormVisible = false;
this.fetchRoleList();
}
});
} else {
return false;
}
});
},
this.$refs[formName].validate((valid) => {...});
:通过this.$refs[formName]
可以获取到表单组件的引用,然后调用validate
方法对表单进行验证。当验证完成后,会执行回调函数中的代码。(valid) => {...}
:这是一个箭头函数,接受一个参数valid
,表示表单验证的结果。箭头函数内部的代码将在表单验证完成后执行。if (valid) {...}
:如果表单验证通过,则执行条件语句中的代码。roleApi.addRole(this.role.name).then((response) => {...});
:调用roleApi
中的addRole
方法,传入角色名称this.role.name
作为参数,发送添加角色的请求。然后使用then
方法处理请求的响应。// 引入
import roleApi from "@/api/role";
const resp = response.data;
:将响应的数据存储在变量resp
中。roleApi.addRole(this.role.name)
方法发送添加角色的请求,然后使用.then()
方法来处理请求的响应。在响应的回调函数中,接收一个参数response
,它包含了从服务器返回的完整的响应对象,其中包括响应的状态码、响应头部和响应体等信息。if (resp.status == 0) {...}
:如果响应的状态为0,表示添加角色成功,则执行条件语句中的代码。this.roleFormVisible = false;
:将角色表单的可见性设置为false,即隐藏角色表单。this.fetchRoleList();
:调用fetchRoleList
方法,重新获取角色列表。this.fetchRoleList()
方法,很可能是为了在成功添加角色后更新角色列表的显示。通过重新获取角色列表,可以确保在用户添加角色后,界面上能够及时更新显示最新的角色信息。else { return false; }
:如果表单验证未通过,则返回false。代表添加角色功能成功实现,并且在前端中会有对应显示:
点击添加角色后弹出弹窗:
1.选中列表中某一行数据后将设置角色权限按钮取消禁用状态(判断currentRow是否为null)
(1)默认设置权限按钮是禁用状态,由于状态需要切换,故使用v-bind双向绑定
(2)为表单中可能点击的每行内容添加
@current-change="handleCurrentChange"
这样的话,在选中需要选择行时,其状态会发生改变,调用handleCurrentChange功能
(3)在methods中创建该方法
handleCurrentChange(val) {
this.currentRow = val;
},
即行从null被切换成val(当前选中行) 并打开权限设置按钮
2.html模板中添加弹窗,弹窗中确定按钮点击事件回调函数需在methods中进行定义(updateRole)
(1)为角色添加权限弹窗
本身 :visible.sync="roleAuthVisible"中的roleAuthVisible是false,但由于在第一步中,设置权限按钮被打开,该按钮中的click功能将roleAuthVisible设置为了true,故此处弹窗显示
注:其中的 :visible.sync="roleAuthVisible"
:visible指的是属性绑定,表示弹框的显示隐藏,当:visible的值为ture的时候,弹框显示,当为false的时候,弹框隐藏
后面的.sync是什么意思呢,指的就是同步动态双向的来表示visible的值,当我们关闭窗口的时候,这个弹框隐藏了,visible的值发生了变化,但是关闭窗口这个动作,我们没法用确定的动作去判断这个值,所以用到了vue中的双向绑定的原则,在vue中统一加上了.sync来表示同步的修改了visible的值。
关于字符串"auth" :
在这段代码中,字符串"auth"作为`ref`属性的值,用于在组件中标识一个引用。通过`this.$refs['auth']`可以获取到这个组件的实例,进而调用该实例的方法或访问其属性。在`updateRole()`方法中,通过`this.$refs['auth'].getMenus()`来获取特定组件实例的`getMenus()`方法的返回值。
3.为设置角色权限按钮添加点击事件,点击按钮弹窗展示(roleAuthVisible设置为true)参考2的(1)
(1)首先设置第一行(上半部分):角色名称
在Auth.vue中:
在这段代码中,`updateRole`是一个对象,用于存储角色信息,包括角色名称。初始值为空字符串。
`roleRules`是一个对象,用于定义表单验证规则。在此例中,`name`属性的验证规则为必填项,如果未填写会显示"请输入角色名称"的提示信息。
`mounted`是Vue实例的生命周期钩子函数,在组件挂载到页面后被调用。在这个函数内部,首先通过`props`接收到父组件传递过来的`role`信息,并用扩展运算符`...`将其值复制给`updateRole`,这样就能在本组件中使用`this.role`。(展开role中的内容--解构赋值--并将其以对象的形式传递给空字符串updateRole以存储传递过来的信息)
接着,对`authList`和`checkedKeys`进行了初始化。
`authList`是一个空数组,用于存储树形空间元素节点。
`checkedKeys`是一个数组,保存了已选中的节点的key值,用于标识角色权限。
总体而言,这段代码是为了在组件渲染后,初始化角色信息和表单验证规则,并进行相关的数据处理。
(2)在父组件Role.vue中引入子组件Auth.vue
引入:
import Auth from "./Auth.vue"
注册:
components: {
Auth,
},
在权限弹窗中显示该组件:
上述框中部分是Element UI组件库中的el-tree
组件来创建一个树形结构的列表
(authList与checkedKeys是在该组件中创建的数组)
:data="authList"
:将 authList
数据绑定到树组件的 data
属性,用于渲染树的节点。show-checkbox
:设置树节点前显示复选框,允许用户选择多个节点。node-key="index"
:设置树节点的键值为 index
,用于唯一标识每个节点。:default-expanded-all="true"
:默认展开所有的节点。:default-checked-keys="checkedKeys"
:使用 checkedKeys
变量作为默认选中的节点。@check-change="handleCheckChange"
:当树节点选择状态发生改变时,触发 handleCheckChange
方法。总的来说,这段代码是创建了一个可以展示和操作树形结构的列表,通过配置属性和事件来实现默认展开、默认选中节点以及处理节点选中状态的功能。
// 根据权限列表数组将元素对象中的属性替换为树形控件中的名称
getAuthNodes(menuList){
return menuList.map((item)=>{
// 一级列表
if(!item.children){
return{
index:item.index,
label:item.title,
};
}else{
// 多级列表
return{
index:item.index,
label:item.title,
// 递归处理多级列表
children:this.getAuthNodes(item.children)
}
}
})
},
getAuthNodes(menuList) 是一个递归方法,用于将权限列表数组(menuList)转化为树形结构的节点数组。
对于每个权限项(item),如果它没有子项(!item.children),则直接将该项的index和title转化为节点对象。 如果有子项,则递归地调用getAuthNodes方法,将子项(item.children)作为参数,获取子节点数组,并将其作为当前节点的children属性的值。
handleCheckChange(data, checked, indeterminate)
是一个方法,用于处理树形控件中的节点复选框状态改变时触发的事件。
// 树形控件元素点击回调
handleCheckChange(data,checked,indeterminate){
if(checked){
// 如果选中项不是students并且在选中项数组中不存在,再添加到数组中,防止重复添加
if(data.index != "/students" && this.checkedKeys.indexOf(data.index) == -1){
this.checkedKeys.push(data.index)
}
}else{
// 判断当前要删除的元素是在数组中存在的
if(this.checkedKeys.indexOf(data.index) > 0){
this.checkedKeys.splice(this.checkedKeys.indexOf(data.index),1)
}
}
console.log("this.checkedKeys",this.checkedKeys);
},
checked
为true
)且该节点不是"/students",且在选中项数组this.checkedKeys
中不存在该节点的键值,则将该节点的键值添加到this.checkedKeys
数组中。checked
为false
),则判断该节点的键值在this.checkedKeys
数组中是否存在,若存在才能将该节点的键值从this.checkedKeys
数组中删除。并传递给父组件updateRole()方法的menus属性值
// 为父组件提供数据(选中了哪些权限---checkedKeys)
getMenus(){
this.updateRole.menus = this.checkedKeys
return this.updateRole
}
关于字符串"auth" :
在这段代码中,字符串"auth"作为`ref`属性的值,用于在组件中标识一个引用。通过`this.$refs['auth']`可以获取到这个组件的实例,进而调用该实例的方法或访问其属性。在`updateRole()`方法中,通过`this.$refs['auth'].getMenus()`来获取特定组件实例的`getMenus()`方法的返回值。
// 点击确定更新角色权限
updateRole(){
const newRole = this.$refs['auth'].getMenus()
this.currentRow.menus = newRole.menus
this.currentRow.name = newRole.name
this.currentRow.auth_name = memoryUtils.user.username
roleApi.update(this.currentRow).then(response=>{
const resp = response.data
if(resp.status == 0 ){
this.$message({
type:'success',
message:'设置角色权限成功!'
})
}
this.roleAuthVisible = false
this.fetchRoleList()
})
}
this.$refs['auth']
引用的组件调用getMenus()
方法,以获取选中的菜单节点数据,将返回的结果保存在newRole
变量中。newRole
中的menus
和name
属性赋值给this.currentRow
对象(选中的对象)的相应属性。memoryUtils.user.username
)赋值给this.currentRow.auth_name
属性。roleApi.update(this.currentRow)
方法,以更新当前角色this.currentRow
。roleApi.update
方法的响应结果:
response
)中的status
等于0,说明角色权限设置成功,显示一个成功的消息通知。this.roleAuthVisible
设为false
,关闭角色权限设置窗口。fetchRoleList()
方法,重新获取角色列表。(8)在子组件Auth.vue中设置mounted()
this.checkedKeys = this.role.menus
和 this.updateRole.menus = this.checkedKeys
具有不同的作用和意义:
this.checkedKeys = this.role.menus
:
this.role.menus
的值赋给 this.checkedKeys
。this.role.menus
是一个属性,它的值可能是一个数组,用于表示已选中的菜单节点。this.checkedKeys
是一个变量,它用于存储选中节点的键值。this.updateRole.menus = this.checkedKeys
:
this.checkedKeys
的值赋给 this.updateRole.menus
。this.updateRole
是一个对象,它是通过 this.role
进行浅拷贝创建的。this.updateRole.menus
是 this.updateRole
对象的一个属性,用于存储选中的菜单节点。this.updateRole
对象中,以便在父组件中使用。总的来说,this.checkedKeys = this.role.menus
将 this.role.menus
的值赋给 this.checkedKeys
,而 this.updateRole.menus = this.checkedKeys
将 this.checkedKeys
的值赋给 this.updateRole.menus
。这样做的目的是为了在不修改原始数据的情况下,分别在不同的变量中存储菜单节点的选中状态,以供不同的功能或组件使用。
(因为要将刚才设置的一系列权限内容保存到数据库中)
(1)设置角色权限
// 设置角色权限
router.post("/manage/role/update",(req,res)=>{
const role = req.body
role.auth_time=Date.now()
RoleModel.findOneAndUpdate({_id:role._id},role).then(oldRole=>{
res.send({status:0,data:{...oldRole._doc,...role}})
}).catch(error=>{
console.log("添加角色异常",error);
res.send({status:1,msg:'添加角色异常,请重试'})
})
})
req.body
获取请求体中的角色数据,保存在role
变量中。role.auth_time
设置为当前时间(Date.now()
),表示更新角色权限的时间。RoleModel
模型的findOneAndUpdate
方法,在数据库中查找指定_id
的角色并更新。oldRole
和更新后的角色role
组合成一个新的对象,作为响应结果的data
字段,同时将status
设为0,表示成功。msg
字段,将status
设为1,表示失败。res.send()
方法将响应结果返回给客户端。(2) 在前端的src的api的role.js中设置向后端发送Post请求
update(role){
return request({
url:'/manage/role/update',
method:'post',
data:role
})
}
// 点击确定更新角色权限
updateRole(){
const newRole = this.$refs['auth'].getMenus()
this.currentRow.menus = newRole.menus
this.currentRow.name = newRole.name
this.currentRow.auth_name = memoryUtils.user.username
roleApi.update(this.currentRow).then(response=>{
const resp = response.data
if(resp.status == 0 ){
this.$message({
type:'success',
message:'设置角色权限成功!'
})
}
this.roleAuthVisible = false
this.fetchRoleList()
})
}
this.$refs['auth']
引用的组件调用getMenus()
方法,以获取选中的菜单节点数据,将返回的结果保存在newRole
变量中。newRole
中的menus
和name
属性赋值给this.currentRow
对象(选中的对象)的相应属性。memoryUtils.user.username
)赋值给this.currentRow.auth_name
属性。roleApi.update(this.currentRow)
方法,以更新当前角色this.currentRow
。roleApi.update
方法的响应结果:
response
)中的status
等于0,说明角色权限设置成功,显示一个成功的消息通知。this.roleAuthVisible
设为false
,关闭角色权限设置窗口。fetchRoleList()
方法,重新获取角色列表。