Vue实现菜单收藏功能

1.功能背景介绍

当许多系统的页面数量达到一定规模时,我们会引入菜单收藏功能。其目的在于让不同用户在使用系统时,能够将自己使用频率较高的页面进行收藏添加。这样,下次用户使用时,便可直接通过自己的收藏菜单进入相应页面进行操作。最终效果如下:

2.项目介绍

项目主要由菜单链接添加、收藏菜单添加及收藏菜单渲染及回显三个模块构成。

2.1 常用链接添加

首先需要完成的就是将整个菜单树进行组装,用于勾选相应的菜单进行添加。

这个模块中,最为重要的一点是需将后端传递过来的菜单树,借助 Element UI 提供的 el-tree 组件进行渲染。

以下是在 Vue 中渲染菜单树的前端代码如下:

 <el-tree class="tree-border" :data="menuOptions" show-checkbox ref="menu" node-key="menuId"
  :default-checked-keys="this.menuIdList" :check-strictly="true" empty-text="加载中,请稍后" :filter-node-method="filterNode":props="defaultProps">
</el-tree>
​
属性介绍
:data 整个菜单树的数据来源
ref 为数绑定的引用名称
show-checkbox 控制是否显示复选框
node-key 节点的关键字,我这里是使用的菜单id作为关键字
:default-checked-keys 默认勾选的数据集,可以用于菜单数据回显
:check-strictly="true" 父子节点关联,为true则关联,为false则不关联.在关联的情况下,选中子节点,父节点也会被选中.
empty-text 数据渲染前的提示
:filter-node-method 数据过滤绑定的方法,配合搜索进行检索

数据源menuOptions通过请求后端进行复制,代码如下:

  /** 查询菜单下拉树结构 */
    getTreeselect() {
      listMenu().then(response => {
          this.menuOptions = [];
          const menu = { menuId: 0, label: '我的管理系统', disabled: true, children: [] };
          const filteredData = response.data.filter(item => item.menuType !== 'F').map(item => {
          const newItem = { ...item, label: item.menuName, disabled: item.menuType === 'M' && item.menuName !== '我的音乐' };
            return newItem;});
                menu.children = this.handleTree(filteredData, "menuId");
                // console.log('wwdwdw', menu)
                this.menuOptions.push(menu);
                console.log('菜单数据树', this.menuOptions)
            });
        },

其中,menuOptions需要在 data 中自行定义。通过 listMenu 请求后端,获取相应数据 response。拿到数据后,由于后端数据结构的原因,需要对其进行过滤,筛选出二级菜单并排除增删改查按钮。具体情况可根据实际需求而定。

2.2 数据选中提交事件

菜单树已渲染完成,接下来需要对渲染出来的菜单树进行选择并添加到后端,同时要对已经存在的菜单进行数据回显。

菜单数据选中方法如下,其中需要对已经被勾选的数据进行过滤:

 // 所有菜单节点数据
 getMenuAllCheckedKeys() {
   // 目前被选中的菜单节点
   let checkedKeys = this.$refs.menu.getCheckedKeys();   //这里要注意的是refs后面的menu一定要跟前面菜单树的ref一致
   // 半选中的菜单节点
   // let halfCheckedKeys = this.$refs.menu.getHalfCheckedKeys(); //可选
   checkedKeys.unshift.apply(checkedKeys);
     
   // 对选中的菜单节点checkedKeys进行过滤已经选中的数据,this.menuIdList里面放的是回显的数据(后端查询的)
   const uniqueNewCheckedKeys = checkedKeys.filter(menuId =>!this.menuIdList.includes(menuId));
   eturn uniqueNewCheckedKeys;
  }

接下来就是后端请求

//添加收藏菜单
Menuconfirm() {
   this.addForm.menuList = this.getMenuAllCheckedKeys();
   console.log("选中菜单数据为", this.addForm)
   addMenuList(this.addForm).then(response => {
      if (response.code == 200) {
          this.$message.success(response.msg)
         }
       });
          console.log('选中的菜单数据为', this.selectedMenuData);
          this.addForm.menuList = this.selectedMenuData;
          console.log('选中的菜单数据2为', this.addForm);
          this.SelectList();
          this.dialogVisible = false
        }

这里的this.addForm.menuList就是我们获取的选中菜单数组,后面就是常规的axios请求及相关操作。

后端拿到前端传递过来的数据后,对其进行相应判断和添加(根据自己的情况而定,我的不一定适合你们)。

   
 @PostMapping
    public AjaxResult add(@RequestBody MyMenuListVo myMenuVO) {
        int successCount = 0;
        for (int i =0; i<myMenuVO.getMenuList().size(); i++){
        Long id = new Long(String.valueOf(myMenuVO.getMenuList().get(i)));
        SysMenu sysMenu = menuService.selectMenuById(id);
        if (sysMenu.getParentId() !=0 || sysMenu.getMenuName().equals("我的桌面")){
            MyMenuList myMenuList = new MyMenuList();
            myMenuList.setUserId(myMenuVO.getUserId());
            myMenuList.setMenuName(sysMenu.getMenuName());
            myMenuList.setMenuId(sysMenu.getMenuId());
            if (sysMenu.getMenuName().equals("我的桌面") ){
                myMenuList.setMenuPath('/'+sysMenu.getPath());
            } else {
                String oldPath =menuService.selectMenuById(sysMenu.getParentId()).getPath();
                myMenuList.setMenuPath('/'+oldPath+'/'+sysMenu.getPath());
            }
            if (myMenuListServer.insertMyMenuList(myMenuList)> 0) {
                successCount++;
            }
        }
        }
        return toAjax(successCount);
    }

2.3 已收藏菜单渲染及美化

后端就是一个普通的get查询,根据登录的用户id或者能够标识用户唯一性的属性进行查询。

 @GetMapping("/list")
    public AjaxResult select(String userId) {
        return AjaxResult.success(myMenuListServer.selectMeunListByUser(userId));
 }

前端对后端给定的数据进行相应渲染

 <div style="display: flex; flex-flow: wrap; margin-top: 16px; ">
       <button v-for="item in currentPageItems" :key="item.uid" @click="getUrlRouter(item.menuPath)" class="boxDiv">
  <div>
        <i class="el-icon-link" style=" font-size: 16px;"></i>{{ item.menuName }}
  </div>
     </button>
 </div>
  <div style=" text-align: center;"> <!-- 分页组件 -->
     <el-pagination @current-change="handleCurrentChange" :current-page="currentPage" :page-size="pageSize"
layout="prev, next" :total="totalItems" />
  </div>

相应的CSS样式代码:

<style scoped>
.boxDiv {
    height: 40px;
    width: 120px;
    border: 1px solid #3271fd;
    background-color: white;
    margin-right: 15px;
    border-radius: 5px;
    text-align: center;
    line-height: 40px;
    margin-bottom: 12px;
}
​
.boxDiv:hover {
    background-color: #3271fd;
    color: white;
    transform: translateY(-5px);
}
​
.addBtn:hover {
    color: #3271fd;
}
​
.addBtn {
    background-color: white;
    border: 0px;
}
​
::v-deep .el-dialog {
    border-radius: 10px;
}
​
::v-deep .el-dialog__body {
    padding-bottom: 15px;
}
​
::v-deep .el-dialog__header {
    margin-bottom: 0px;
    background-color: #0176e3;
}
​
::v-deep .el-dialog__title,
::v-deep .el-dialog__headerbtn .el-dialog__close {
    color: white;
}
​
::v-deep .el-pagination .btn-prev .el-icon,
::v-deep .el-pagination .btn-next .el-icon {
    font-size: 16px;
    margin-right: 50px;
}
</style>

最后还要对已经收藏的菜单数据进行一个回显操作。

//查询收藏菜单&菜单数据回显   myMenuList接收收藏菜单,menuIdList接收回显菜单Id集合
SelectList() {
  selectMenuList(this.addForm.userId).then((response) => {
  this.myMenuList = response.data
  this.menuIdList = response.data.map(item => item.menuId);
  console.log(this.menuIdList)
  });
},

3.疑难点

  1. 需要在后端对菜单树的数据进行相应的组装,然后传递给前端。

  2. 在数据回显的过程中,务必注意在新增操作时,一定要将回显的数据进行过滤,否则会出现重复添加的情况。另外一种方法是在每次添加时,先将该用户在数据库中的收藏菜单全部删除,然后再次重新添加,这样也可以避免重复添加。

  3. 菜单树的子父级选中关联可根据自身情况决定。这里不希望选中父节点时所有子节点就被自动选中,所以进行了一些处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ctrl+c程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值