Now to implement a cascading menu function, I do not want to use Element to implement, because I am afraid that the function will be added later, and it may be more troublesome to change based on element. I prefer the feeling of control from beginning to end.
A few things to consider:
- How to design the data structure to populate the cascading menu (see Element’s tree)
- How to cascade this effect (recursively calling the component itself)
- How does each menu know which of the props it is?
- How do I send the message that I clicked on this menu? (By routing)
- How to indent the next level relative to the last (CSS)
Without further ado, go straight to the code:
The first is the data structure to pass into the cascading menu:
// Where path corresponds to the following component name and route name, name is the name of each item to be displayed in the menu, children is the child menu, Content is the same as the parent menuDetail: [{path: '... ', name: '... 'children: [...]}, {...}]Copy the code
The general idea is that the cascade menu creates one component, Cascad-menu, which is equivalent to the general management, creating one component, Cascad-item, for each item in the menu. The key idea of cascad-item design is that each item should know its own level of which, otherwise it can not be activated and data transfer. The NTH item in this array represents the NTH level, and the number in each item represents the number of active items. When you click on the menu item, in addition to changing the CSS, you also need to pass information to the menu to change the array, indicating that the active menu has changed. If it has changed, because props, Item is also known.
The way to do this is to use a cascading menu of your own design in other components, passing in the populated data. It’s very simple
<cascade-menu :dataContent="menuDetail"></cascade-menu>
Copy the code
Let’s start with the overall component design
// <template> <div> <cascade-item... V-for ="(item,index) of dataContent"> </ cascad-item > </div> </template> <script> import CascadeItem from './CascadeItem'; Export default{props:['dataContent'], data(){return{// keep track of the index for each level of the menu. ActiveIndexArray :[-1],}}, Methods :{// Give activeIndexArray onChangeActiveIndex(Payload){... }, /* select * from 'content' where 'path' is' content 'where' item 'is' index' where 'path' is' index 'where' path 'is' content' where 'item' is' index 'where' path 'is' index' where 'path' is' content 'where' item 'is' index' where 'path' is' index 'where' path 'is' content' where 'item' is' index 'where' path 'is' index' */ findItem(content,item,index,track){... }, // Go to dataConten and assign activeIndexArray changeActiveIndexArray(itemToFind){... }}, mounted(){// watch:{// monitor the route, If change the routing after the change of name to this. ChangeActiveIndexArray run}} < / script >Copy the code
The second is the design of a single item of the cascading menu
<template> <div ref="menu" class="menu-name"> <! - its name -- -- > < div @ click = "onClickMenu ref =" name ":" class = "{... }"> {{dataFilling.name}} <i ref="arrow" class="el-icon-arrow-down zm-arrow" v-if="dataFilling.children"></i> </div> <! --> <div ref=" 70f3 "v-if="dataFilling. Children "> <cas-cad-item... </cas-cad-item> </div> </div> </template> <script> Export default{/* LevelCount: the number of levels in which it is located index: the order in which it is located parentIndex: the array in which it is located from the highest level to the lowest level. ActiveIndexArray: Records the active index */ for each layer of the cascading menu Props :['dataFilling','levelCount','index','parentIndex','activeIndexArray'], computed:{level:{// return levelCount}, // Select activeSelf:function () {// Select activeSelf:function () {// Select activeSelf:function () {// Select activeSelf:function () {// Select activeSelf; // Otherwise there will be only the most sublevel activation, The parent does not activate the return this. LevelArray. ToString () = = = this. ActiveIndexArray. Slice (0, this. LevelArray. Length). The toString (); }, LevelArray :function () {// add this.index to this.parentIndex array}}, Data (){return{spreadChildren:false}}, {onChangeActiveIndex(payload){this.$emit('changeActiveIndex',payload); // Emit ('changeActiveIndex',payload); }, // Modify the arrow and submenu to open the folded CSS modifyChildrenCSS(){/* Here can't use document.querySelector(' I ') to use $refs to reference the DOM The main method is to rotate the arrow and fold the submenu by controlling the addition or removal of an active class name. $emit('changeActiveIndex',payload); // emit(' spreadChildren ',payload); // emit(' spreadChildren ',payload); this.modifyChildrenCSS(); */ } }, mounted(){ let name=this.$refs.name; name.style.paddingLeft=`${(this.level+1)*20}px`; // The menu component will render before the menu component. // The menu component will render before the menu component. SetTimeout (()=>{setTimeout()=>{ if(this.levelArray.toString()===this.activeIndexArray.slice(0,this.levelArray.length).toString()){ this.spreadChildren=true; this.modifyChildrenCSS(); Word-wrap: break-word! Important; "> < span style =" box-sizing: border-box; color: RGB (50, 50, 50); */ </style> </style> </style>Copy the code
In fact, there is a flaw in the design, that is, the tree structure should be designed like the Element. The key that fills the data can be specified by itself. I am limited here.