LayUI + Shiro + Thyemleaf は動的メニューを実装し、メニューの拡張と縮小を記憶します 1. Maven 依存関係<依存関係> <!--Ali FastJson 依存関係--> <依存関係> <グループID>com.alibaba</グループID> <artifactId>fastjson</artifactId> <バージョン>1.2.39</バージョン> </依存関係> <!--権限制御--> <依存関係> <グループID>org.apache.shiro</グループID> <artifactId>shiro-spring-boot-starter</artifactId> <バージョン>1.4.0-RC2</バージョン> </依存関係> <!-- thymeleaf の shiro と互換性があります --> <依存関係> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <バージョン>2.0.0</バージョン> </依存関係> <依存関係> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </依存関係> <依存関係> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </依存関係> <依存関係> <グループ ID>org.mybatis.spring.boot</グループ ID> <artifactId>mybatis-spring-boot-starter</artifactId> <バージョン>2.1.4</バージョン> </依存関係> <依存関係> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>ランタイム</scope> <オプション>true</オプション> </依存関係> <依存関係> <グループID>mysql</グループID> <artifactId>mysql-コネクタ-java</artifactId> <scope>ランタイム</scope> </依存関係> <依存関係> <groupId>org.projectlombok</groupId> <artifactId>ロンボク</artifactId> <オプション>true</オプション> </依存関係> <依存関係> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>テスト</scope> </依存関係> </依存関係> 2. メニュー関連クラス1. メインメニュー/** * @author wxhntmy */ @ゲッター @セッター パブリッククラスメニュー{ プライベート文字列名; プライベート文字列アイコン; プライベート文字列 URL; プライベートブール値 hidden; プライベート List<MenuList> リスト; } 2. サブメニュー/** * @author wxhntmy */ @ゲッター @セッター パブリッククラスMenuList { プライベート文字列名; プライベート文字列 URL; パブリックメニューリスト(文字列名、文字列URL) { this.name = 名前; this.url = url; } } 3. Shiroの設定1. シロコンフィグ/** * @author wxhntmy */ @構成 パブリッククラスShiroConfig{ /** * インターセプターを構成する * <p> * インターセプト URL 権限を定義します。上から下の優先順位は 1)。anon: 匿名アクセス、ログイン不要 2)。authc: ログインが必要 3)。logout: ログアウト 4)。 * ロール: ロールフィルター * <p> * URL マッチング スタイル 1)。?: は文字に一致します。たとえば、/admin? は /admin1 に一致しますが、/admin や /admin/ には一致しません。2)。 * *: 0 個以上の文字列に一致します。たとえば、/admin* は /admin または /admin123 に一致しますが、/admin/1 には一致しません。2)。 * **: パス内の0個以上のパスに一致します。たとえば、/admin/** は /admin/a または /admin/a/b に一致します。 * <p> * 認証成功と認証失敗のジャンプパスを設定する*/ @ビーン パブリック ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = 新しい ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(); // 静的リソースへの匿名アクセス filterChainDefinitionMap.put("/layui/**", "anon"); フィルターチェーン定義マップ.put("/js/**", "anon"); フィルターチェーン定義マップ.put("/admin/**", "anon"); フィルターチェーン定義マップ.put("/**/*.eot", "anon"); フィルターチェーン定義マップ.put("/**/*.svg", "anon"); フィルターチェーン定義マップ.put("/**/*.svgz", "anon"); フィルターチェーン定義マップ.put("/**/*.ttf", "anon"); フィルターチェーン定義マップ.put("/**/*.woff", "anon"); フィルターチェーン定義マップ.put("/**/*.woff2", "anon"); フィルターチェーン定義マップ.put("/**/*.gif", "anon"); filterChainDefinitionMap.put("/favicon.ico", "anon"); フィルターチェーン定義マップ.put("/login", "anon"); filterChainDefinitionMap.put("/menu", "anon"); filterChainDefinitionMap.put("/user/login", "anon"); // ユーザーログアウト filterChainDefinitionMap.put("/logout", "logout"); // 他のパスは ID 認証を必要とし、通常は最も優先順位の低い一番下にあります。filterChainDefinitionMap.put("/**", "authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); //ログインパス shiroFilterFactoryBean.setLoginUrl("/login"); // ホームページ //shiroFilterFactoryBean.setSuccessUrl("/index"); //検証失敗のジャンプパス shiroFilterFactoryBean.setUnauthorizedUrl("/error"); shiroFilterFactoryBean を返します。 } /** * SecurityManager セキュリティマネージャ。shiro の中核* * @戻る */ @ビーン パブリックDefaultWebSecurityManagerセキュリティマネージャ() { デフォルトの Web セキュリティ マネージャー defaultWeb セキュリティ マネージャー = 新しい DefaultWeb セキュリティ マネージャー (myRealm())。 defaultWebSecurityManager を返します。 } /** * カスタムレルム * * @戻る */ @ビーン パブリックMyRealm myRealm() { MyRealm myRealm = 新しい MyRealm(); myRealm.setCredentialsMatcher(myCredentialsMatcher()); myRealm を返します。 } /** * 暗号化方式を設定する * @return */ @ビーン パブリック MyCredentialsMatcher myCredentialsMatcher() { 新しい MyCredentialsMatcher() を返します。 } /** * Shiro ライフサイクルプロセッサを構成する */ @ビーン パブリックライフサイクルBeanPostProcessorライフサイクルBeanPostProcessor() { 新しい LifecycleBeanPostProcessor() を返します。 } /** * プロキシクラスを自動的に作成します。追加しないと、Shiro のアノテーションが有効にならない場合があります。 */ @ビーン @DependsOn({ "ライフサイクルBeanポストプロセッサ" }) パブリックDefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator アドバイザーAutoProxyCreator = 新しい DefaultAdvisorAutoProxyCreator(); advisorAutoProxyCreator.setProxyTargetClass(true); advisorAutoProxyCreator を返します。 } /** * Shiro注釈を有効にする*/ @ビーン パブリック AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() { AuthorizationAttributeSourceAdvisor の authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager()); authorizationAttributeSourceAdvisor を返します。 } @ビーン パブリック ShiroDialect shiroDialect() { 新しい ShiroDialect() を返します。 } } 2. Shiroのパスワード認証をカスタマイズする/** * カスタム shiro パスワード検証 * @author wxhntmy */ パブリッククラス MyCredentialsMatcher は CredentialsMatcher を実装します { @リソース プライベート UserMapper userMapper; @オーバーライド パブリックブールdoCredentialsMatch(AuthenticationTokenトークン、AuthenticationInfo情報) { ユーザー名パスワードトークン utoken = (ユーザー名パスワードトークン) トークン; 文字列パスワード = 新しい文字列(utoken.getPassword()); 文字列ユーザー名 = utoken.getUsername(); ユーザー user = userMapper.getUserById(username); user.getPwd().equals(password) を返します。 } } 3. マイレルム /** * @author wxhntmy */ パブリッククラスMyRealmはAuthorizingRealmを拡張します{ @リソース プライベート RoleMapper roleMapper; @リソース プライベート UserRoleListMapper userRoleListMapper; // 承認 @Override 保護された AuthorizationInfo doGetAuthorizationInfo(プリンシパルコレクション プリンシパルコレクション) { SimpleAuthorizationInfo の authorizationInfo = 新しい SimpleAuthorizationInfo(); ユーザー user = (User) principalCollection.getPrimaryPrincipal(); (ユーザー == null)の場合{ null を返します。 } リスト<UserRoleList> roleLists = userRoleListMapper.getUserRoleByUserId(user.getId()); リスト<Role> roles = roleMapper.getAllRoles(); (roleLists != null && !roleLists.isEmpty())の場合 { (UserRoleList ロールリスト: ロールリスト) { (ロール ロール: ロール) { (Objects.equals(roleList.getRole_id(), role.getId())) の場合 { 認可情報にロールを追加します(ロールを取得します)。 } } } } authorizationInfo を返します。 } //認証@オーバーライド 保護されたAuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) はAuthenticationExceptionをスローします { //ログインユーザーアカウントを取得します。UsernamePasswordToken utoken = (UsernamePasswordToken) authenticationToken; //ユーザーが入力したパスワードを取得します。String password = new String(utoken.getPassword()); 文字列ユーザー名 = utoken.getUsername(); ユーザー user = new User(); user.setId(ユーザー名); user.setPwd(パスワード); //現在のレルム オブジェクトの一意の名前。親クラスの getName() メソッドを呼び出します。String realmName = getName(); // ソルト値、つまりユーザー名を取得します。ByteSource salt = ByteSource.Util.bytes(password); SimpleAuthenticationInfo 情報 = 新しい SimpleAuthenticationInfo(ユーザー、パスワード、ソルト、レルム名); 情報を返します。 } } 4. コントロール1. ログインコントローラ@レストコントローラ パブリッククラスLoginController { @リソース プライベート RoleMapper roleMapper; @リソース プライベート UserRoleListMapper userRoleListMapper; @リソース プライベート UserMapper userMapper; @RequestMapping(値 = "/user/login", メソッド = RequestMethod.GET) パブリックMsg<String> getUserByName(@RequestParam String user, @RequestParam 文字列 pwd、 @RequestParam 文字列 ユーザータイプ、 @RequestParam 文字列ボックス) { ロール role = roleMapper.getRoleByRoleName(usertype); ユーザー uUser = userMapper.getUserById(user); (uUser == null)の場合{ Msg.fail("UserUnexit"); を返します。 } //ログイン認証 UsernamePasswordToken token = new UsernamePasswordToken(user, pwd); 件名 subject = SecurityUtils.getSubject(); 試す { subject.login(トークン); } キャッチ (認証例外 e) { Msg.fail("PasswordError"); を返します。 } //ログインの有効期限をミリ秒単位で設定します。ここでは 30 分に設定されています。SecurityUtils.getSubject().getSession().setTimeout(1800000); Msg.ok("成功") を返します。 } } 2. ページコントローラ@コントローラ パブリッククラス PageController { @リソース プライベート UserMapper userMapper; @RequestMapping(値 = "/login", メソッド = RequestMethod.GET) パブリック文字列ログイン(){ 「ログイン」を返します。 } @RequestMapping(値 = "/user/index", メソッド = RequestMethod.GET) パブリック文字列インデックス(モデルモデル){ ユーザー user = (User) SecurityUtils.getSubject().getPrincipal(); ユーザー uuser = userMapper.getUserById(user.getId()); StringUtils.isEmpty(ユーザー)の場合{ 「redirect:/login」を返します。 } モデルに属性を追加します("user", uuser); 「インデックス」を返します。 } } 3. メニューコントローラー/** * @author wxhntmy */ @レストコントローラ パブリッククラスMenuController{ @リソース プライベート RoleMapper roleMapper; @リソース プライベート UserRoleListMapper userRoleListMapper; //ユーザー メニュー コレクションを記憶します private Map<String, Map> menu_map = new HashMap<>(); @RequestMapping(値 = "/menu", メソッド = RequestMethod.GET) パブリック Msg<List<Menu>> getMenu() { ユーザー user = (User) SecurityUtils.getSubject().getPrincipal(); リスト<メニュー> リスト = 新しい ArrayList<>(); StringUtils.isEmpty(ユーザー)の場合{ return Msg.fail(list, "ログイン情報の有効期限が切れています。もう一度ログインしてください!"); } // Map<String, Boolean> を収集することを忘れないでください。map_store = new HashMap<>(); (menu_map.containsKey(user.getId()))の場合{ map_store = menu_map.get(user.getId()); } Map<String, String> map = new HashMap(); リスト<UserRoleList> roleLists = userRoleListMapper.getUserRoleByUserId(user.getId()); (UserRoleList ロールリスト: ロールリスト) { ロール role = roleMapper.getRoleByRoleId(roleList.getRole_id()); ロールの取得ロール()、ロールリストの取得ユーザーID() をマップします。 } メニュー menu1 = new Menu(); menu1.setName("ホーム"); menu1.setIcon(""); menu1.setUrl("/user/index"); menu1.setHidden(false); リスト<MenuList> menuLists2 = 新しいArrayList<>(); メニュー1.setList(メニューリスト2); リストに追加(メニュー1) map.containsKey("学生")の場合{ メニュー menu2 = new Menu(); メニュー menu3 = new Menu(); menu2.setName("コース管理"); menu2.setIcon(""); menu2.setUrl(""); menu2.setHidden(map_store.getOrDefault("コース管理", false)); リスト<MenuList> menuLists = 新しいArrayList<>(); MenuList menuList1 = new MenuList("選択したコース", ""); MenuList menuList2 = new MenuList("オプションコース", ""); MenuList menuList22 = new MenuList("コースフォーラム", ""); メニューリストを追加します(メニューリスト1)。 メニューリストを追加します(メニューリスト2)。 メニューリストを追加します(メニューリスト22); menu2.setList(メニューリスト); menu3.setName("パフォーマンス管理"); menu3.setIcon(""); menu3.setUrl(""); menu3.setHidden(map_store.getOrDefault("パフォーマンス管理", false)); リスト<MenuList> menuLists3 = 新しいArrayList<>(); MenuList menuList3 = new MenuList("コース結果の送信", ""); MenuList menuList33 = new MenuList("コースログの送信", ""); MenuList menuList4 = new MenuList("実習コースの結果", ""); MenuList menuList5 = new MenuList("コースアンケート", ""); メニューリスト3を追加します。 メニューリスト3.add(メニューリスト33); メニューリスト3.add(メニューリスト4); メニューリスト3.add(メニューリスト5); メニュー3.setList(メニューリスト3); リストに追加(メニュー2) リストに追加します(メニュー3)。 } map.containsKey("先生"){ メニュー menu2 = new Menu(); メニュー menu3 = new Menu(); menu2.setName("コース管理"); menu2.setIcon(""); メニュー2.setUrl(""); menu2.setHidden(map_store.getOrDefault("コース管理", false)); リスト<MenuList> menuLists = 新しいArrayList<>(); MenuList menuList1 = new MenuList("教授のトレーニングコース", ""); MenuList menuList2 = new MenuList("コースフォーラム", ""); メニューリストを追加します(メニューリスト1)。 メニューリストを追加します(メニューリスト2)。 menu2.setList(メニューリスト); menu3.setName("パフォーマンス管理"); menu3.setIcon(""); menu3.setUrl(""); menu3.setHidden(map_store.getOrDefault("パフォーマンス管理", false)); リスト<MenuList> menuLists3 = 新しいArrayList<>(); MenuList menuList3 = new MenuList("コース達成度チェック", ""); MenuList menuList33 = new MenuList("コースログ承認", ""); MenuList menuList4 = new MenuList("実習コースの結果", ""); メニューリスト3を追加します。 メニューリスト3.add(メニューリスト33); メニューリスト3.add(メニューリスト4); メニュー3.setList(メニューリスト3); リストに追加(メニュー2) リストに追加します(メニュー3)。 } if (map.containsKey("専門家")){ メニュー menu2 = new Menu(); メニュー menu3 = new Menu(); menu2.setName("実習コース運営"); menu2.setIcon(""); メニュー2.setUrl(""); menu2.setHidden(map_store.getOrDefault("実習コース運営", false)); リスト<MenuList> menuLists = 新しいArrayList<>(); MenuList menuList1 = new MenuList("認定対象となる実習コース", ""); MenuList menuList2 = new MenuList("トレーニングコースの追加", ""); MenuList menuList3 = new MenuList("実習コース運営", ""); メニューリストを追加します(メニューリスト1)。 メニューリストを追加します(メニューリスト2)。 メニューリストを追加します(メニューリスト3)。 menu2.setList(メニューリスト); menu3.setName("アンケートを公開"); menu3.setIcon(""); menu3.setUrl(""); menu3.setHidden(map_store.getOrDefault("アンケートを公開", false)); リスト<MenuList> menuLists1 = 新しいArrayList<>(); MenuList menuList11 = new MenuList("アンケートを公開", ""); MenuList menuList21 = new MenuList("回復アンケート", ""); メニューリスト1.add(メニューリスト11); メニューリスト1.add(メニューリスト21); メニュー3.setList(メニューリスト1); リストに追加(メニュー2) リストに追加します(メニュー3)。 } map.containsKey("admin") の場合{ メニュー menu2 = new Menu(); メニュー menu3 = new Menu(); menu2.setName("ユーザー管理"); menu2.setIcon(""); menu2.setUrl(""); menu2.setHidden(map_store.getOrDefault("ユーザー管理", false)); リスト<MenuList> menuLists = 新しいArrayList<>(); MenuList menuList0 = new MenuList("ユーザーの追加", ""); MenuList menuList1 = new MenuList("学生アカウント", ""); MenuList menuList2 = new MenuList("教師アカウント", ""); MenuList menuList3 = new MenuList("研修担当者アカウント", ""); メニューリストを追加します(メニューリスト0)。 メニューリストを追加します(メニューリスト1)。 メニューリストを追加します(メニューリスト2)。 メニューリストを追加します(メニューリスト3)。 menu2.setList(メニューリスト); menu3.setName("データベース管理"); menu3.setIcon(""); menu3.setUrl(""); menu3.setHidden(map_store.getOrDefault("データベース管理", false)); リスト<MenuList> menuLists3 = 新しいArrayList<>(); MenuList menuList4 = new MenuList("データベースのバックアップ", ""); MenuList menuList5 = new MenuList("データベースを復元", ""); メニューリスト3.add(メニューリスト4); メニューリスト3.add(メニューリスト5); メニュー3.setList(メニューリスト3); リストに追加(メニュー2) リストに追加します(メニュー3)。 } メニュー menu4 = new Menu(); menu4.setName("システム設定"); menu4.setIcon(""); menu4.setUrl(""); menu4.setHidden(map_store.getOrDefault("システム設定", false)); リスト<MenuList> menuLists4 = 新しいArrayList<>(); MenuList menuList5 = new MenuList("個人情報の変更", ""); MenuList menuList6 = new MenuList("パスワードの変更", ""); MenuList menuList7 = new MenuList("キャッシュをクリア", ""); メニューリスト4.add(メニューリスト5); メニューリスト4.add(メニューリスト6); メニューリスト4.add(メニューリスト7); メニュー4.setList(メニューリスト4); メニュー menu5 = new Menu(); menu5.setName("ログアウト"); menu5.setIcon(""); menu5.setUrl("/ログアウト"); menu5.setHidden(false); リスト<MenuList> menuLists5 = 新しいArrayList<>(); メニュー5.setList(メニューリスト5); リストに追加(メニュー4) リストに追加(メニュー5) map.containsKey("学生")の場合{ Msg.ok(リスト、"STU")を返します。 } 文字列メッセージ = null; map.containsKey("先生")の場合{ メッセージ = "TEA"; } if (map.containsKey("専門家")){ メッセージ = "PRI"; } map.containsKey("admin") の場合{ メッセージ = "ADM"; } Msg.ok(リスト、メッセージ)を返します。 } @RequestMapping(値 = "/menu_storage", メソッド = RequestMethod.GET) パブリックMsg<String> menu_storage(@RequestParam String data) { JSONArray の jsonArray を JSONArray.parseArray(data) に変換します。 ユーザー user = (User) SecurityUtils.getSubject().getPrincipal(); StringUtils.isEmpty(ユーザー)の場合{ return Msg.fail("ログイン情報の有効期限が切れています。再度ログインしてください!"); } // Map<String, Boolean> を収集することを忘れないでください。map_store = new HashMap<>(); (オブジェクト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); Msg.ok() を返します。 } } 5. データベース1. ユーザーテーブル 2. 役割表 3. user_role_list テーブル 6. フロントエンドページ1. Ajaxリクエストメニューデータconfig = {} とします。 関数set_menu() { //ajax 情報を送信$.ajax({ タイプ: "get", 非同期: false、 url: "/menu", // リクエストはLoginServletに送信されます dataType: 'json', 成功: 関数 (メッセージ) { msg.ok === true の場合、msg.data は次のようになります。 config["name"] = msg.message; config["メニュー"] = msg.data; } msg.ok が false の場合 window.location.href = "/ログアウト"; } if (!msg.data) { window.location.href = "/ログアウト"; } }, エラー: 関数 (メッセージ) { // リクエストが失敗したときにこの関数を実行します。layer.alert('メニューデータのリクエストに失敗しました!!!', function (index) { //何かをする レイヤーを閉じます(インデックス); }); } }); } set_menu(); $(ドキュメント).ready(関数() { //削除$(".del").click(function() { var url = $(this).attr("href"); var id = $(this).attr("データID"); layer.confirm('本当に削除しますか?', { ボタン: ['OK', 'キャンセル'] }、 関数 () { $.get(url, 関数(データ) { (データコード === 1)の場合{ $(id).fadeOut(); レイヤー.msg(データ.msg、{アイコン: 1}); } それ以外 { レイヤー.msg(data.msg, {アイコン: 2}); } }); }、 関数 () { layer.msg("削除をキャンセルしました!"); }); false を返します。 }); }) layui.use('form', 関数() { var フォーム = layui.form, レイヤー = layui.layer; }); var vue = 新しい Vue({ el: '#app', データ: { ウェブ名: config.name、 メニュー: [], 住所: [] }, 作成: 関数 () { config.menu をカスタマイズします。 this.thisActive(); this.thisAttr(); }, メソッド: { // onActiveを閉じることを忘れないでください: function (pid, id = false) { データを入力します。 id === falseの場合{ データ = this.menu[pid]; (data.url.length > 0) の場合 { this.menu.forEach((v, k) => { v.active = false; v.list.forEach((v2, k2) => { アクティブ = false; }) }) データアクティブ = true; } データ.hidden = !データ.hidden; } それ以外 { this.menu.forEach((v, k) => { v.active = false; v.list.forEach((v2, k2) => { アクティブ = false; }) }) データ = this.menu[pid].list[id]; } this.updateStorage(); (data.url.length > 0) の場合 { if (データ.ターゲット) { (data.target === '_blank')の場合{ ウィンドウを開きます(data.url); } それ以外 { データURLをコピーします。 } } それ以外 { データURLをコピーします。 } } }, //メニューキャッシュを更新する updateStorage() { //sessionStorage.menu = JSON.stringify(this.menu); $.ajax({ タイプ: "get", 非同期: false、 url: "/menu_storage", // リクエストはLoginServletに送信されます data: { "データ": JSON.stringify(this.menu) }, データ型: 'json', 成功: 関数 (メッセージ) { }, エラー: 関数 (メッセージ) { // リクエストが失敗したときにこの関数を実行します var index = layer.load(); レイヤーを閉じます(インデックス); layer.alert('メニューデータの要求に失敗しました!!!', function (index) { //何かをする レイヤーを閉じます(インデックス); }); } }); }, //メニューのハイライト thisActive: function () { pathname = window.location.pathname; とします。 ホストを window.location.host とします。 pid = false とします。 id = false とします。 this.menu.forEach((v, k) => { url = v.url; とします。 url.length > 0 の場合 { url[0] !== '/' && url.substr(0, 4) !== 'http' の場合 { url = '/' + url; } } if (パス名 === URL) { pid = k; } v.list.forEach((v2, k2) => { url = v2.url; とします。 url.length > 0 の場合 { url[0] !== '/' && url.substr(0, 4) !== 'http' の場合 { url = '/' + url; } } if (パス名 === URL) { pid = k; id = k2; } }) }) id !== false の場合 { this.menu[pid].list[id].active = true; } それ以外 { pid !== false の場合 { this.menu[pid].active = true; } } this.updateStorage(); }, //現在の位置 thisAttr: function () { //現在の位置 let address = [{ 名前: 'ホームページ', URL: '/user/index' }]; this.menu.forEach((v, k) => { v.list.forEach((v2, k2) => { (v2.active) の場合 { アドレス.push({ 名前: v.name、 url: 'javascript:;' }) アドレス.push({ 名前: v2.name、 URL: v2.url、 }) this.address = アドレス; } }) }) } } }) 2. メニューバーを表示する<ul class="cl"> <!--トップカテゴリー--> <li v-for="vo,メニュー内のインデックス" :class="{hidden:vo.hidden}"> <a href="javascript:;" rel="外部nofollow" rel="外部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,vo.list のインデックス2"> <a href="javascript:;" rel="外部 nofollow" rel="外部 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> 7. 完全なコードコード転送を完了しました Gitee: wxhntmy/SpringBootLayuiMenu これで、LayUI+Shiro の動的メニューの実装例とメニューの拡大と縮小を記憶する例についての記事は終了です。LayUI Shiro の動的メニューに関するその他の関連コンテンツについては、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。 以下もご興味があるかもしれません:
|
<<: Linux で nginx を起動および再起動する方法
>>: docker ベースの redis-sentinel クラスターの構築例
この記事は主に、nginx を介して方向プロキシを実装するプロセスを紹介します。この記事のサンプル ...
MySQL カスタム値は、値を保存するための一時的なコンテナです。サーバーへの接続がアクティブである...
この記事では、複数の画像を切り替えるJavaScriptの具体的なコードを参考までに紹介します。具体...
この記事では、libudev ライブラリを使用して hidraw デバイスにアクセスします。 lib...
ネットワークの問題のトラブルシューティング、新しい接続のセットアップ、ファイアウォールの構成を行うと...
ステップ1: MySQLドライバをダウンロードするcmdは作成されたDjangoプロジェクトディレク...
目次1. パッケージングツールでのカスタムインポート2. ブラウザとバンドラの共通インポート構文3....
Bツリーインデックス異なるストレージ エンジンでは、異なるストレージ構造を使用する場合もあります。た...
1. MYSQLインデックスインデックス: MySQL がデータを効率的に取得するのに役立つデータ構...
top コマンドは、Linux システムのパフォーマンスを監視するために誰もが使用している最適なコマ...
CSS ビューポート ユニットはここ数年登場しており、時が経つにつれて、ますます多くの開発者が使用し...
タブバー: 異なるタブをクリックすると異なるコンテンツが表示され、クリックしたタブのスタイルが変更さ...
以下のように表示されます。 //managefee_managefee テーブルの年と月を照会し、c...
プロジェクトでは、現在地の緯度経度を取得したり、場所を検索して緯度経度情報を取得したりする必要があり...
フォルダー内のすべての txt ファイルのファイル名の前に「gt_」を追加する必要があります。つまり...