Vue.js菜单权限项目问题:子子菜单在所有表格单元格异常显示
问题解决方法
你的问题出在子子菜单的过滤逻辑没有和当前行的菜单绑定:当前的filteredSub_submenu计算属性是全局过滤所有选中子菜单对应的子子菜单,然后在每一行的单元格里都渲染这个全局结果,所以所有行都会显示相同的子子菜单。
具体修改步骤:
- 替换全局计算属性为行级过滤方法
把原来的filteredSub_submenu计算属性改成一个接收菜单ID的方法,这样可以针对每一行的菜单,只筛选属于该菜单下的子菜单对应的子子菜单:
methods: { // 保留原有的setSelectedMenu、setSelectedSubMenu方法 getFilteredSubSubmenus(menuId) { // 先获取当前菜单下的所有子菜单ID const currentMenuSubmenuIds = this.submenus .filter(sub => sub.menuId === menuId) .map(sub => sub.id); // 结合选中的子菜单来过滤子子菜单 if (this.selectedSubMenu.includes("0")) { // 选中"全部"时,只显示当前菜单下的子子菜单 return this.subsubmenus.filter(item => currentMenuSubmenuIds.includes(item.submenuId)); } else { // 只显示选中的子菜单且属于当前菜单的子子菜单 return this.subsubmenus.filter(item => { return this.selectedSubMenu.includes(item.submenuId) && currentMenuSubmenuIds.includes(item.submenuId); }); } } }
- 修改模板中的子子菜单渲染逻辑
在表格的Sub-Submenu单元格里,调用这个方法并传入当前行的menu.id,这样每一行只会渲染属于自己菜单下的子子菜单:
<td> <ul> <li v-for="subsubmenu in getFilteredSubSubmenus(menu.id)" :key="subsubmenu.id"> <label> <input type="checkbox" :value="subsubmenu.id" /> {{ subsubmenu.sub_subMenuName }} </label> </li> </ul> </td>
- 可选优化:修复子菜单的渲染效率
原来的子菜单渲染是先循环所有filteredProduct再用v-if判断,改成直接在循环里过滤更高效:
<td> <ul> <li v-for="submenu in getCurrentMenuSubmenus(menu.id)" :key="submenu.id" > <label> <input type="checkbox" :value="submenu.id" @change="setSelectedSubMenu($event,submenu.id)" /> {{ submenu.subMenuName }} </label> </li> </ul> </td>
对应的新增方法:
getCurrentMenuSubmenus(menuId) { if (this.selectedMenu.includes("0")) { return this.submenus.filter(sub => sub.menuId === menuId); } else { return this.submenus.filter(sub => sub.menuId === menuId && this.selectedMenu.includes(sub.menuId)); } }
修改后的完整代码
HTML部分
<!-- Include the library in the page --> <script src="https://unpkg.com/vue@2.2.0-beta.1/dist/vue.js"></script> <!-- App --> <div id="app"> <table class="table"> <thead> <tr> <th>Menu</th> <label><input type="checkbox" v-model="selectedMenu" value="0" /> All</label> <th>Submenu</th> <th>Sub-Submenu</th> </tr> </thead> <tbody> <tr v-for="menu in menus" :key="menu.id"> <td> <label> <input type="checkbox" :value="menu.id" @change="setSelectedMenu($event,menu.id)" />{{ menu.menuName }} </label> </td> <td> <ul> <li v-for="submenu in getCurrentMenuSubmenus(menu.id)" :key="submenu.id" > <label> <input type="checkbox" :value="submenu.id" @change="setSelectedSubMenu($event,submenu.id)" /> {{ submenu.subMenuName }} </label> </li> </ul> </td> <td> <ul> <li v-for="subsubmenu in getFilteredSubSubmenus(menu.id)" :key="subsubmenu.id"> <label> <input type="checkbox" :value="subsubmenu.id" /> {{ subsubmenu.sub_subMenuName }} </label> </li> </ul> </td> </tr> </tbody> </table> </div>
JavaScript部分
console.clear() // New VueJS instance var app = new Vue({ el: "#app", data: { menus: [{ id: 1, menuName: "Tech 1" }, { id: 2, menuName: "Tech 2" }, { id: 3, menuName: "Tech 3" } ], selectedMenu: [], submenus: [{ id: 1, menuId: 1, subMenuName: "architecture" }, { id: 2, menuId: 1, subMenuName: "Electrical" }, { id: 3, menuId: 1, subMenuName: "Electronics" }, { id: 4, menuId: 2, subMenuName: "IEM" }, { id: 5, menuId: 3, subMenuName: "CIVIL" } ], selectedSubMenu: [], subsubmenus: [{ id: 1, submenuId: 1, sub_subMenuName: "becm" }, { id: 2, submenuId: 1, sub_subMenuName: "ece" }, { id: 3, submenuId: 4, sub_subMenuName: "EEE" }, { id: 4, submenuId: 2, sub_subMenuName: "CSE" }, { id: 5, submenuId: 3, sub_subMenuName: "MSE" } ], }, computed: { filteredProduct: function() { const app = this, menu = app.selectedMenu; if (menu.includes("0")) { return app.submenus; } else { return app.submenus.filter(function(item) { return menu.indexOf(item.menuId) >= 0; }); } } }, methods: { setSelectedMenu: function(event, menu_id) { if (event.target.checked) { this.selectedMenu.push(menu_id); } else { var index = this.selectedMenu.indexOf(menu_id); this.selectedMenu.splice(index, 1); } }, setSelectedSubMenu: function(event, submenu_id) { if (event.target.checked) { this.selectedSubMenu.push(submenu_id); } else { var index = this.selectedSubMenu.indexOf(submenu_id); this.selectedSubMenu.splice(index, 1); } }, getCurrentMenuSubmenus(menuId) { if (this.selectedMenu.includes("0")) { return this.submenus.filter(sub => sub.menuId === menuId); } else { return this.submenus.filter(sub => sub.menuId === menuId && this.selectedMenu.includes(sub.menuId)); } }, getFilteredSubSubmenus(menuId) { const currentMenuSubmenuIds = this.submenus .filter(sub => sub.menuId === menuId) .map(sub => sub.id); if (this.selectedSubMenu.includes("0")) { return this.subsubmenus.filter(item => currentMenuSubmenuIds.includes(item.submenuId)); } else { return this.subsubmenus.filter(item => { return this.selectedSubMenu.includes(item.submenuId) && currentMenuSubmenuIds.includes(item.submenuId); }); } } } })
CSS部分
ul { list-style-type: none; margin: 0; padding: 0; }
核心原理
通过给每一行的子子菜单渲染绑定当前菜单ID,确保过滤逻辑只针对当前菜单下的子菜单集合,这样选中子菜单后,只有对应父菜单所在的行才会显示其下属的子子菜单,不会全局显示。
内容的提问来源于stack exchange,提问作者16_018_RHR
相关产品推荐
相关产品推荐

