LayUI+Shiro实现动态菜单并记住菜单收展的示例

2022-04-15 0 671
目录
  • 一、Maven 依赖
  • 二、菜单相关的类
    • 1、主菜单
    • 2、子菜单
  • 三、Shiro 配置
    • 1、ShiroConfig
    • 2、自定义shiro密码校验
  • 四、控制类
    • 1、LoginController
    • 2、PageController
    • 3、MenuController
  • 五、数据库
    • 六、前端页面
      • 1、Ajax 请求菜单数据
      • 2、显示菜单栏
    • 七、完整代码

      LayUI + Shiro + Thyemleaf 实现动态菜单并记住菜单收展

      LayUI+Shiro实现动态菜单并记住菜单收展的示例

      LayUI+Shiro实现动态菜单并记住菜单收展的示例

      一、Maven 依赖

      <dependencies>
      
              <!--阿里 FastJson依赖-->
              <dependency>
                  <groupId>com.alibaba</groupId>
                  <artifactId>fastjson</artifactId>
                  <version>1.2.39</version>
              </dependency>
              <!--权限控制 -->
              <dependency>
                  <groupId>org.apache.shiro</groupId>
                  <artifactId>shiro-spring-boot-starter</artifactId>
                  <version>1.4.0-RC2</version>
              </dependency>
      
              <!-- 兼容于thymeleaf的shiro -->
              <dependency>
                  <groupId>com.github.theborakompanioni</groupId>
                  <artifactId>thymeleaf-extras-shiro</artifactId>
                  <version>2.0.0</version>
              </dependency>
      
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-thymeleaf</artifactId>
              </dependency>
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-web</artifactId>
              </dependency>
              <dependency>
                  <groupId>org.mybatis.spring.boot</groupId>
                  <artifactId>mybatis-spring-boot-starter</artifactId>
                  <version>2.1.4</version>
              </dependency>
      
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-devtools</artifactId>
                  <scope>runtime</scope>
                  <optional>true</optional>
              </dependency>
              <dependency>
                  <groupId>mysql</groupId>
                  <artifactId>mysql-connector-java</artifactId>
                  <scope>runtime</scope>
              </dependency>
              <dependency>
                  <groupId>org.projectlombok</groupId>
                  <artifactId>lombok</artifactId>
                  <optional>true</optional>
              </dependency>
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-test</artifactId>
                  <scope>test</scope>
              </dependency>
          </dependencies>
      

      二、菜单相关的类

      1、主菜单

      LayUI+Shiro实现动态菜单并记住菜单收展的示例

      /**
       * @author wxhntmy
       */
      @Getter
      @Setter
      public class Menu {
          private String name;
          private String icon;
          private String url;
          private Boolean hidden;
          private List<MenuList> list;
      }
      

      2、子菜单

      LayUI+Shiro实现动态菜单并记住菜单收展的示例

      /**
       * @author wxhntmy
       */
      @Getter
      @Setter
      public class MenuList {
          private String name;
          private String url;
      
          public MenuList(String name, String url) {
              this.name = name;
              this.url = url;
          }
      }
      

      三、Shiro 配置

      1、ShiroConfig

      /**
       * @author wxhntmy
       */
      @Configuration
      public class ShiroConfig {
          /**
           * 配置拦截器
           * <p>
           * 定义拦截URL权限,优先级从上到下 1). anon : 匿名访问,无需登录 2). authc : 登录后才能访问 3). logout: 登出 4).
           * roles : 角色过滤器
           * <p>
           * URL 匹配风格 1). ?:匹配一个字符,如 /admin? 将匹配 /admin1,但不匹配 /admin 或 /admin/; 2).
           * *:匹配零个或多个字符串,如 /admin* 将匹配 /admin 或/admin123,但不匹配 /admin/1; 2).
           * **:匹配路径中的零个或多个路径,如 /admin/** 将匹配 /admin/a 或 /admin/a/b
           * <p>
           * 配置身份验证成功,失败的跳转路径
           */
          @Bean
          public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
              ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
              shiroFilterFactoryBean.setSecurityManager(securityManager);
              Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
      
              // 静态资源匿名访问
              filterChainDefinitionMap.put("/layui/**", "anon");
              filterChainDefinitionMap.put("/js/**", "anon");
              filterChainDefinitionMap.put("/admin/**", "anon");
      
              filterChainDefinitionMap.put("/**/*.eot", "anon");
              filterChainDefinitionMap.put("/**/*.svg", "anon");
              filterChainDefinitionMap.put("/**/*.svgz", "anon");
              filterChainDefinitionMap.put("/**/*.ttf", "anon");
              filterChainDefinitionMap.put("/**/*.woff", "anon");
              filterChainDefinitionMap.put("/**/*.woff2", "anon");
              filterChainDefinitionMap.put("/**/*.gif", "anon");
      
              filterChainDefinitionMap.put("/favicon.ico", "anon");
      
              filterChainDefinitionMap.put("/login", "anon");
              filterChainDefinitionMap.put("/menu", "anon");
              filterChainDefinitionMap.put("/user/login", "anon");
      
              // 用户退出
              filterChainDefinitionMap.put("/logout", "logout");
      
      
              // 其他路径均需要身份认证,一般位于最下面,优先级最低
              filterChainDefinitionMap.put("/**", "authc");
      
              shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
              //登录路径
              shiroFilterFactoryBean.setLoginUrl("/login");
              // 主页
              //shiroFilterFactoryBean.setSuccessUrl("/index");
              //验证失败跳转的路径
              shiroFilterFactoryBean.setUnauthorizedUrl("/error");
              return shiroFilterFactoryBean;
          }
      
          /**
           * SecurityManager安全管理器;shiro的核心
           * 
           * @return
           */
          @Bean
          public DefaultWebSecurityManager securityManager() {
              DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager(myRealm());
              return defaultWebSecurityManager;
          }
      
          /**
           * 自定义Realm
           * 
           * @return
           */
          @Bean
          public MyRealm myRealm() {
              MyRealm myRealm = new MyRealm();
              myRealm.setCredentialsMatcher(myCredentialsMatcher());
              return myRealm;
          }
      
          /**
           * 配置加密方式
           * @return
           */
          @Bean
          public MyCredentialsMatcher myCredentialsMatcher() {
              return new MyCredentialsMatcher();
          }
      
          /**
           * 配置Shiro生命周期处理器
           */
          @Bean
          public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
              return new LifecycleBeanPostProcessor();
          }
      
          /**
           * 自动创建代理类,若不添加,Shiro的注解可能不会生效。
           */
          @Bean
          @DependsOn({ "lifecycleBeanPostProcessor" })
          public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
              DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
              advisorAutoProxyCreator.setProxyTargetClass(true);
              return advisorAutoProxyCreator;
          }
      
          /**
           * 开启Shiro的注解
           */
          @Bean
          public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
              AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
              authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
              return authorizationAttributeSourceAdvisor;
          }
      
          @Bean
          public ShiroDialect shiroDialect() {
              return new ShiroDialect();
          }
      }
      

      2、自定义shiro密码校验

      /**
       * 自定义shiro密码校验
       * @author wxhntmy
       */
      public class MyCredentialsMatcher implements CredentialsMatcher {
      
          @Resource
          private UserMapper userMapper;
      
          @Override
          public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
      
              UsernamePasswordToken utoken = (UsernamePasswordToken) token;
      
              String password = new String(utoken.getPassword());
              String username = utoken.getUsername();
      
              User user = userMapper.getUserById(username);
      
              return user.getPwd().equals(password);
          }
      }
      

      3、MyRealm

      /**
       * @author wxhntmy
       */
      public class MyRealm extends AuthorizingRealm {
      
          @Resource
          private RoleMapper roleMapper;
          @Resource
          private UserRoleListMapper userRoleListMapper;
      
          //授权
          @Override
          protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
      
              SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
      
              User user = (User) principalCollection.getPrimaryPrincipal();
              if (user == null) {
                  return null;
              }
      
      
              List<UserRoleList> roleLists = userRoleListMapper.getUserRoleByUserId(user.getId());
      
              List<Role> roles = roleMapper.getAllRoles();
      
              if (roleLists != null && !roleLists.isEmpty()) {
                  for (UserRoleList roleList : roleLists) {
                      for (Role role : roles) {
                          if (Objects.equals(roleList.getRole_id(), role.getId())) {
                              authorizationInfo.addRole(role.getRole());
                          }
                      }
                  }
              }
              return authorizationInfo;
          }
      
          //认证
          @Override
          protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
              //获取登录用户账号
              UsernamePasswordToken utoken = (UsernamePasswordToken) authenticationToken;
      
              //获得用户输入的密码
              String password = new String(utoken.getPassword());
              String username = utoken.getUsername();
      
              User user = new User();
      
              user.setId(username);
              user.setPwd(password);
      
              //当前realm对象的唯一名字,调用父类的getName()方法
              String realmName = getName();
      
              // 获取盐值,即用户名
              ByteSource salt = ByteSource.Util.bytes(password);
      
              SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, salt, realmName);
      
              return info;
      
          }
      
      }
      

      四、控制类

      1、LoginController

      @RestController
      public class LoginController {
      
          @Resource
          private RoleMapper roleMapper;
          @Resource
          private UserRoleListMapper userRoleListMapper;
          @Resource
          private UserMapper userMapper;
      
          @RequestMapping(value = "/user/login", method = RequestMethod.GET)
          public Msg<String> getUserByName(@RequestParam String user,
                                           @RequestParam String pwd,
                                           @RequestParam String usertype,
                                           @RequestParam String box) {
      
      
              Role role = roleMapper.getRoleByRoleName(usertype);
              User uUser = userMapper.getUserById(user);
              if (uUser == null){
                  return Msg.fail("UserUnexit");
              }
              //登录验证
              UsernamePasswordToken token = new UsernamePasswordToken(user, pwd);
              Subject subject = SecurityUtils.getSubject();
              try {
                  subject.login(token);
              } catch (AuthenticationException e) {
                  return Msg.fail("PasswordError");
              }
              //设置登陆过期时间,单位毫秒,这里设置30分钟
              SecurityUtils.getSubject().getSession().setTimeout(1800000);
              return Msg.ok("Success");
          }
      }
      

      2、PageController

      @Controller
      public class PageController {
      
          @Resource
          private UserMapper userMapper;
      
          @RequestMapping(value = "/login", method = RequestMethod.GET)
          public String Login(){
              return "login";
          }
      
          @RequestMapping(value = "/user/index", method = RequestMethod.GET)
          public String Index(Model model){
      
              User user = (User) SecurityUtils.getSubject().getPrincipal();
      
              User uuser = userMapper.getUserById(user.getId());
      
              if (StringUtils.isEmpty(user)) {
                  return "redirect:/login";
              }
      
              model.addAttribute("user", uuser);
      
              return "index";
          }
      }
      

      3、MenuController

      /**
       * @author wxhntmy
       */
      @RestController
      public class MenuController {
      
          @Resource
          private RoleMapper roleMapper;
          @Resource
          private UserRoleListMapper userRoleListMapper;
      
          //记住用户菜单收展
          private Map<String, Map> menu_map = new HashMap<>();
      
          @RequestMapping(value = "/menu", method = RequestMethod.GET)
          public Msg<List<Menu>> getMenu() {
              User user = (User) SecurityUtils.getSubject().getPrincipal();
      
              List<Menu> list = new ArrayList<>();
      
              if (StringUtils.isEmpty(user)) {
                  return Msg.fail(list, "登录信息已过期!请重新登录!");
              }
      
              //记住收展
              Map<String, Boolean> map_store = new HashMap<>();
      
              if (menu_map.containsKey(user.getId())){
                  map_store = menu_map.get(user.getId());
              }
      
              Map<String, String> map = new HashMap();
              List<UserRoleList> roleLists = userRoleListMapper.getUserRoleByUserId(user.getId());
              for (UserRoleList roleList : roleLists) {
                  Role role = roleMapper.getRoleByRoleId(roleList.getRole_id());
                  map.put(role.getRole(), roleList.getUser_id());
              }
              Menu menu1 = new Menu();
              menu1.setName("首页");
              menu1.setIcon("");
              menu1.setUrl("/user/index");
              menu1.setHidden(false);
      
              List<MenuList> menuLists2 = new ArrayList<>();
              menu1.setList(menuLists2);
              list.add(menu1);
      
      
              if (map.containsKey("student")){
                  Menu menu2 = new Menu();
                  Menu menu3 = new Menu();
      
                  menu2.setName("课程管理");
                  menu2.setIcon("");
                  menu2.setUrl("");
                  menu2.setHidden(map_store.getOrDefault("课程管理", false));
                  List<MenuList> menuLists = new ArrayList<>();
                  MenuList menuList1 = new MenuList("已选课程", "");
                  MenuList menuList2 = new MenuList("可选课程", "");
                  MenuList menuList22 = new MenuList("课程论坛", "");
                  menuLists.add(menuList1);
                  menuLists.add(menuList2);
                  menuLists.add(menuList22);
                  menu2.setList(menuLists);
      
                  menu3.setName("成果管理");
                  menu3.setIcon("");
                  menu3.setUrl("");
                  menu3.setHidden(map_store.getOrDefault("成果管理", false));
                  List<MenuList> menuLists3 = new ArrayList<>();
                  MenuList menuList3 = new MenuList("提交课程成果", "");
                  MenuList menuList33 = new MenuList("提交课程日志", "");
                  MenuList menuList4 = new MenuList("实训课程成绩", "");
                  MenuList menuList5 = new MenuList("课程调查问卷", "");
                  menuLists3.add(menuList3);
                  menuLists3.add(menuList33);
                  menuLists3.add(menuList4);
                  menuLists3.add(menuList5);
                  menu3.setList(menuLists3);
      
                  list.add(menu2);
                  list.add(menu3);
              }
      
              if (map.containsKey("teacher")){
                  Menu menu2 = new Menu();
                  Menu menu3 = new Menu();
      
                  menu2.setName("授课课程管理");
                  menu2.setIcon("");
                  menu2.setUrl("");
                  menu2.setHidden(map_store.getOrDefault("授课课程管理", false));
                  List<MenuList> menuLists = new ArrayList<>();
                  MenuList menuList1 = new MenuList("教授的实训课程", "");
                  MenuList menuList2 = new MenuList("课程论坛", "");
                  menuLists.add(menuList1);
                  menuLists.add(menuList2);
                  menu2.setList(menuLists);
      
                  menu3.setName("成果管理");
                  menu3.setIcon("");
                  menu3.setUrl("");
                  menu3.setHidden(map_store.getOrDefault("成果管理", false));
                  List<MenuList> menuLists3 = new ArrayList<>();
                  MenuList menuList3  = new MenuList("课程成果检查", "");
                  MenuList menuList33 = new MenuList("课程日志批复", "");
                  MenuList menuList4  = new MenuList("实训课程成绩", "");
                  menuLists3.add(menuList3);
                  menuLists3.add(menuList33);
                  menuLists3.add(menuList4);
                  menu3.setList(menuLists3);
      
                  list.add(menu2);
                  list.add(menu3);
              }
              if (map.containsKey("professionor")){
                  Menu menu2 = new Menu();
                  Menu menu3 = new Menu();
      
                  menu2.setName("实训课程管理");
                  menu2.setIcon("");
                  menu2.setUrl("");
                  menu2.setHidden(map_store.getOrDefault("实训课程管理", false));
                  List<MenuList> menuLists = new ArrayList<>();
                  MenuList menuList1 = new MenuList("待批准实训课程", "");
                  MenuList menuList2 = new MenuList("添加实训课程", "");
                  MenuList menuList3 = new MenuList("实训课程管理", "");
                  menuLists.add(menuList1);
                  menuLists.add(menuList2);
                  menuLists.add(menuList3);
                  menu2.setList(menuLists);
      
                  menu3.setName("发布调查问卷");
                  menu3.setIcon("");
                  menu3.setUrl("");
                  menu3.setHidden(map_store.getOrDefault("发布调查问卷", false));
                  List<MenuList> menuLists1 = new ArrayList<>();
                  MenuList menuList11 = new MenuList("发布调查问卷", "");
                  MenuList menuList21 = new MenuList("回收调查问卷", "");
                  menuLists1.add(menuList11);
                  menuLists1.add(menuList21);
                  menu3.setList(menuLists1);
      
                  list.add(menu2);
                  list.add(menu3);
              }
              if (map.containsKey("admin")){
                  Menu menu2 = new Menu();
                  Menu menu3 = new Menu();
      
                  menu2.setName("用户管理");
                  menu2.setIcon("");
                  menu2.setUrl("");
                  menu2.setHidden(map_store.getOrDefault("用户管理", false));
                  List<MenuList> menuLists = new ArrayList<>();
                  MenuList menuList0 = new MenuList("添加用户", "");
                  MenuList menuList1 = new MenuList("学生账号", "");
                  MenuList menuList2 = new MenuList("教师账号", "");
                  MenuList menuList3 = new MenuList("实训负责人账号", "");
                  menuLists.add(menuList0);
                  menuLists.add(menuList1);
                  menuLists.add(menuList2);
                  menuLists.add(menuList3);
                  menu2.setList(menuLists);
      
                  menu3.setName("数据库管理");
                  menu3.setIcon("");
                  menu3.setUrl("");
                  menu3.setHidden(map_store.getOrDefault("数据库管理", false));
                  List<MenuList> menuLists3 = new ArrayList<>();
                  MenuList menuList4  = new MenuList("备份数据库", "");
                  MenuList menuList5 = new MenuList("还原数据库", "");
                  menuLists3.add(menuList4);
                  menuLists3.add(menuList5);
                  menu3.setList(menuLists3);
      
                  list.add(menu2);
                  list.add(menu3);
              }
      
              Menu menu4 = new Menu();
              menu4.setName("系统设置");
              menu4.setIcon("");
              menu4.setUrl("");
              menu4.setHidden(map_store.getOrDefault("系统设置", false));
              List<MenuList> menuLists4 = new ArrayList<>();
              MenuList menuList5 = new MenuList("修改个人信息", "");
              MenuList menuList6 = new MenuList("修改密码", "");
              MenuList menuList7 = new MenuList("清除缓存", "");
              menuLists4.add(menuList5);
              menuLists4.add(menuList6);
              menuLists4.add(menuList7);
              menu4.setList(menuLists4);
      
              Menu menu5 = new Menu();
              menu5.setName("退出登录");
              menu5.setIcon("");
              menu5.setUrl("/logout");
              menu5.setHidden(false);
              List<MenuList> menuLists5 = new ArrayList<>();
              menu5.setList(menuLists5);
      
              list.add(menu4);
              list.add(menu5);
      
              if (map.containsKey("student")){
                  return Msg.ok(list, "STU");
              }
              String message = null;
              if (map.containsKey("teacher")){
                  message = "TEA";
              }
              if (map.containsKey("professionor")){
                  message = "PRI";
              }
              if (map.containsKey("admin")){
                  message = "ADM";
      
              }
              return Msg.ok(list, message);
          }
      
          @RequestMapping(value = "/menu_storage", method = RequestMethod.GET)
          public Msg<String> menu_storage(@RequestParam String data) {
      
              JSONArray jsonArray = JSONArray.parseArray(data);
              User user = (User) SecurityUtils.getSubject().getPrincipal();
      
              if (StringUtils.isEmpty(user)) {
                  return Msg.fail("登录信息已过期!请重新登录!");
              }
              //记住收展
              Map<String, Boolean> map_store = new HashMap<>();
      
              for (Object o : jsonArray) {
                  JSONObject jsonObject = JSONObject.parseObject(o.toString());
                  map_store.put(jsonObject.getString("name"), Boolean.valueOf(jsonObject.getString("hidden")));
              }
      
              menu_map.put(user.getId(), map_store);
      
              return Msg.ok();
          }
      }
      

      五、数据库

      1、user 表

      LayUI+Shiro实现动态菜单并记住菜单收展的示例

      2、role 表

      LayUI+Shiro实现动态菜单并记住菜单收展的示例

      3、user_role_list 表

      LayUI+Shiro实现动态菜单并记住菜单收展的示例

      六、前端页面

      1、Ajax 请求菜单数据

      		let config = {};
              function set_menu() {
                  //ajax提交信息
                  $.ajax({
                      type: "get",
                      async: false,
                      url: "/menu",// 请求发送到LoginServlet处
                      dataType: 'json',
                      success: function (msg) {
                          if (msg.ok === true && msg.data) {
                              config["name"] = msg.message;
                              config["menu"] = msg.data;
                          }
                          if (msg.ok === false) {
                              window.location.href = "/logout";
                          }
                          if (!msg.data) {
                              window.location.href = "/logout";
                          }
                      },
                      error: function (msg) {
                          // 请求失败时执行该函数
                          layer.alert('请求菜单数据失败!!!', function (index) {
                              //do something
                              layer.close(index);
                          });
                      }
                  });
              }
      
              set_menu();
      
      
              $(document).ready(function () {
                  //删除
                  $(".del").click(function () {
                      var url = $(this).attr("href");
                      var id = $(this).attr("data-id");
      
                      layer.confirm('你确定要删除么?', {
                          btn: ['确定', '取消']
                      }, function () {
                          $.get(url, function (data) {
                              if (data.code === 1) {
                                  $(id).fadeOut();
                                  layer.msg(data.msg, {icon: 1});
                              } else {
                                  layer.msg(data.msg, {icon: 2});
                              }
                          });
                      }, function () {
                          layer.msg("您取消了删除!");
                      });
                      return false;
                  });
              })
      
              layui.use('form', function () {
                  var form = layui.form,
                      layer = layui.layer;
              });
      
              var vue = new Vue({
                  el: '#app',
                  data: {
                      webname: config.name,
                      menu: [],
                      address: []
                  },
                  created: function () {
                      this.menu = config.menu;
                      this.thisActive();
                      this.thisAttr();
                  },
                  methods: {
                      //记住收展
                      onActive: function (pid, id = false) {
                          let data;
                          if (id === false) {
                              data = this.menu[pid];
                              if (data.url.length > 0) {
                                  this.menu.forEach((v, k) => {
                                      v.active = false;
                                      v.list.forEach((v2, k2) => {
                                          v2.active = false;
                                      })
                                  })
                                  data.active = true;
                              }
                              data.hidden = !data.hidden;
                          } else {
                              this.menu.forEach((v, k) => {
                                  v.active = false;
                                  v.list.forEach((v2, k2) => {
                                      v2.active = false;
                                  })
                              })
                              data = this.menu[pid].list[id];
                          }
      
                          this.updateStorage();
                          if (data.url.length > 0) {
                              if (data.target) {
                                  if (data.target === '_blank') {
                                      window.open(data.url);
                                  } else {
                                      window.location.href = data.url;
                                  }
                              } else {
                                  window.location.href = data.url;
                              }
                          }
                      },
      
                      //更新菜单缓存
                      updateStorage() {
                          //sessionStorage.menu = JSON.stringify(this.menu);
                          $.ajax({
                              type: "get",
                              async: false,
                              url: "/menu_storage",// 请求发送到LoginServlet处
                              data: {
                                  "data": JSON.stringify(this.menu)
                              },
                              dataType: 'json',
                              success: function (msg) {
      
                              },
                              error: function (msg) {
                                  // 请求失败时执行该函数
                                  var index = layer.load();
                                  layer.close(index);
                                  layer.alert('请求菜单数据失败!!!', function (index) {
                                      //do something
                                      layer.close(index);
                                  });
                              }
                          });
                      },
                      //菜单高亮
                      thisActive: function () {
                          let pathname = window.location.pathname;
                          let host = window.location.host;
                          let pid = false;
                          let id = false;
                          this.menu.forEach((v, k) => {
                              let url = v.url;
                              if (url.length > 0) {
                                  if (url[0] !== '/' && url.substr(0, 4) !== 'http') {
                                      url = '/' + url;
                                  }
                              }
                              if (pathname === url) {
                                  pid = k;
                              }
                              v.list.forEach((v2, k2) => {
                                  let url = v2.url;
      
                                  if (url.length > 0) {
                                      if (url[0] !== '/' && url.substr(0, 4) !== 'http') {
                                          url = '/' + url;
                                      }
                                  }
                                  if (pathname === url) {
                                      pid = k;
                                      id = k2;
                                  }
                              })
                          })
      
      
                          if (id !== false) {
                              this.menu[pid].list[id].active = true;
                          } else {
                              if (pid !== false) {
                                  this.menu[pid].active = true;
                              }
                          }
      
                          this.updateStorage();
      
                      },
                      //当前位置
                      thisAttr: function () {
                          //当前位置
                          let address = [{
                              name: '首页',
                              url: '/user/index'
                          }];
                          this.menu.forEach((v, k) => {
                              v.list.forEach((v2, k2) => {
                                  if (v2.active) {
                                      address.push({
                                          name: v.name,
                                          url: 'javascript:;'
                                      })
                                      address.push({
                                          name: v2.name,
                                          url: v2.url,
                                      })
                                      this.address = address;
                                  }
                              })
                          })
                      }
                  }
              })
      

      2、显示菜单栏

      <ul class="cl">
              <!--顶级分类-->
              <li v-for="vo,index in menu" :class="{hidden:vo.hidden}">
                  <a href="javascript:;" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  :class="{active:vo.active}" @click="onActive(index)">
                      <i class="layui-icon" v-html="vo.icon"></i>
                      <span v-text="vo.name"></span>
                      <i class="layui-icon arrow" v-show="vo.url.length==0"></i> <i v-show="vo.active"
                                                                                            class="layui-icon active"></i>
                  </a>
                  <!--子级分类-->
                  <div v-for="vo2,index2 in vo.list">
                      <a href="javascript:;" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  :class="{active:vo2.active}" @click="onActive(index,index2)"
                         v-text="vo2.name"></a>
                      <i v-show="vo2.active" class="layui-icon active"></i>
                  </div>
              </li>
          </ul>
      

      七、完整代码

      完整代码转 Gitee:wxhntmy / SpringBootLayuiMenu

      到此这篇关于LayUI+Shiro实现动态菜单并记住菜单收展的示例的文章就介绍到这了,更多相关LayUI Shiro动态菜单内容请搜索NICE源码以前的文章或继续浏览下面的相关文章希望大家以后多多支持NICE源码!

      免责声明:
      1、本网站所有发布的源码、软件和资料均为收集各大资源网站整理而来;仅限用于学习和研究目的,您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。 不得使用于非法商业用途,不得违反国家法律。否则后果自负!

      2、本站信息来自网络,版权争议与本站无关。一切关于该资源商业行为与www.niceym.com无关。
      如果您喜欢该程序,请支持正版源码、软件,购买注册,得到更好的正版服务。
      如有侵犯你版权的,请邮件与我们联系处理(邮箱:skknet@qq.com),本站将立即改正。

      NICE源码网 JavaScript LayUI+Shiro实现动态菜单并记住菜单收展的示例 https://www.niceym.com/34334.html