summary:
tab by default, different dishes displayed under the menu are displayed. The primary routing menu corresponds to various dishes under the secondary routing menu
The routing menu on the left filters out the dish information on the right according to different dish names
The tab bar is mainly displayed on the right, and the corresponding dishes are displayed during switching, as well as the dishes filtered on the left
Code function realization:
tab switch list and function implementation. When clicking switch, the dish information on the right will also change
Left menu filter list: click the selected keyword to filter out the corresponding dishes
The menu list on the right is used to display the dishes filtered in the tab menu bar and the menu bar on the left. When clicking a certain keyword to filter dishes, if there is no matching dish in the dish, let it display a text to increase the user experience
For example, in the effect picture below, when you click "cook", a text is displayed to let others know that there is no corresponding dish under the currently selected keyword
Mask layer: each time data is obtained from the back end, a mask layer is set before data is obtained to avoid the feeling of sudden appearance of data
All codes
<template> <div class="recipe"> <!-- v-model="activeName" --> <!-- Recipe classification start --> <!--tab Switch menu--> <el-tabs v-model="classifyName" type="border-card" @tab-click='tabClick()'> <el-tab-pane :label="item.parent_name" v-for='item in classify' :key='item.parent_type' :name='item.parent_type'> <div class="recipe-link"> <!-- query Pass the value to the original query Bring it here in the original query Add the currently selected classify of option attribute --> <router-link :to="{query:{...$route.query,classify:option.type}}" v-for='option in item.list' :key='option.type' :class="{active:classifyType === option.type }" > <!--Judge current options.type And classifyType Are they equal If equal, bind the currently clicked element active This will achieve the effect that whoever clicks will change his background --> {{option.name}} </router-link> </div> </el-tab-pane> </el-tabs> <!-- Recipe classification end --> <h2>Home style tastes good and gives you the warmth of your home</h2> <el-container> <!-- Left menu list --> <el-aside width="220px" class="recipe-aside"> <div class="filter-box"> <h4>screen</h4> <!-- v-model="activeName" --> <!-- screen start --> <el-collapse v-model="properActiveName"> <el-collapse-item v-for='item in propType' :key='item.parent_type' :title="item.parent_name" :name='item.parent_type' > <div class="filter-tags" > <el-tag type="info" v-for='option in item.list' :key='option.type' @click="selectedTag(option)" :class="{'tag-selected':propertyType[option.title] === option.type}" > {{option.name}} </el-tag> </div> </el-collapse-item> </el-collapse> <!-- screen end --> </div> </el-aside> <el-main class="filter-menus-box"> <div class="menu-empty" v-show='!list.length && !loading' >The menu information is not filtered out temporarily. Please select other filtering criteria</div> <!--Same below if loading or!list.length || loading && !loading --> <!--Work display--> <menu-card style="min-height: 75%;" :info="list"></menu-card> <!-- Pagination display --> <div style="text-align: right;" v-show='!loading'> <el-pagination style="display: inline-block;" :page-size="5" layout="total, prev, pager, next" :total="total" :current-page.sync='page' @current-change="handlerSelect" :hide-on-single-page='true' > </el-pagination> </div> </el-main> </el-container> </div> </template> <script> import MenuCard from '@/components/menu-card.vue' import {getClassify, getProperty, getMenus} from '@/service/api'; export default { components: {MenuCard}, data() { return { classify:[], // Store all data of tab switching propType:[], // Store all data for attributes classifyType:"1-1", // tab selected items for switching (secondary routing) classifyName:'1', // Define the value when refreshing the tab (Level 1 routing) propertyType:{}, // Classification of storage properties. For example: {craft:1-4,flavor=2-1} properActiveName:[], // Record all attribute classifications list:[], // Store right subject data total:0, // PageCount loading:false, // Show mask layer page:1, // the number of pages } }, watch: { $route: { handler(){ const {classify,page} = this.$route.query ; console.log(typeof page) // console.log(this.$route.query,classify) if(classify){ // Take out the attribute stored in classify and assign it to this.classifyType // Exists in the currently selected item this.classifyType = classify ; // 1-1 value of secondary menu this.classifyName = classify[0] ; // 1 value of the first level menu this.page = Number(page) ; } this.getThisMenus() }, immediate:true, } }, mounted() { getClassify().then(({data})=>{ // console.log(data) this.classify = data ; // console.log(!this.$route.query.classify) // If query has no parameters, define an initial value for it, and define the first level and second level in the data as an initial value //Simply put, if there are no parameters, take them from the back end and finally save them back to the route if(!this.$route.query.classify){ this.classifyType = this.classify[0].list[0].type ; // 1-1 this.classifyName = this.classify[0].parent_type ; // 1 // Save the value of the returned component into the route this.$router.push({ query:{ classify:this.classifyType, // page:1 } }) } }); getProperty().then(({data})=>{ this.propType = data ; const {query} = this.$route ; this.propertyType = this.propType.reduce((k,item)=>{ // item.title: craft, difficulty, taste, number of people k[item.title] = query[item.title] ? query[item.title] : "" ; // console.log(item) if(k[item.title]){ this.properActiveName.push(k[item.title][0]) ; // console.log(k[item.title][0],this.properActiveName) } return k ; },{}) // console.log(query,this.propertyType) }) }, methods: { selectedTag(val){ let query = {...this.$route.query} // Judge whether to click. If yes, cancel. Otherwise, select if(this.propertyType[val.title] === val.type){ this.propertyType[val.title] = "" ; delete query[val.title] }else{ this.propertyType[val.title] = val.type ; query[val.title] = val.type } this.$router.push({ query // query:{ // ...this.$route.query, // [val.title]:val.type // } }) }, getThisMenus(){ const query = {...this.$route.query} const params = { page:query.page || '1', classify:query.classify } delete query.page ; delete query.classify ; if(Object.keys(query).length){ params.property = { ...query } } this.loading = true ; let loading = null ; this.$nextTick(()=>{ loading = this.$loading({ lock:true, target:".filter-menus-box", text:'Loading...', spinner:'el-icon-loading', background:'rgba(0,0,0,0.5)' }) }) ; // When filtering dishes, clear its current dish data, and then obtain the filtered dish data, otherwise it will cause existing problems The product suddenly switches to filtered data,It will give people a bad experience this.list = [] ; // Clear the data to display the re requested data // Request data on the right getMenus(params).then(({data})=>{ // console.log(data) if(this.loading){ loading.close() } this.loading = false ; this.list = data.list ; this.total = data.total ; this.page = data.current_page ; // If the loading after obtaining the filtered data is always false, re assign it to make its value true if(this.loading === false){ this.loading = true ; } }) }, handlerSelect(){ this.$router.push({ query:{ ...this.$route.query, page:this.page } }) }, tabClick(){ const classifNames = this.classifyName ; const item = this.classify.find(item => item.parent_type === classifNames) // console.log(item) // item is the first level route (overall data) currently selected or clicked if(item){ this.classifyName = item.parent_type ; // type of first level routing menu this.classifyType = item.list[1].type ; // type of secondary routing menu this.$router.push({ query:{ ...this.$route.query, classify:this.classifyType } }) } } } } </script>
Summary: finally, a small bug in the mask layer will appear. When the routing menu is frequently switched, the dishes will be displayed on the right
The mask layer of the list will make the whole page in the bug that is being refreshed by the mask layer, or enter the recipe from other pages This bug also occurs when
About my solution:
v-show='! list.length || loading && ! loading' js is used here Logical operator
Here, I add another condition to the original condition. It will be triggered only when the first two conditions are met. If the first two conditions are not met, it will look at the later conditions
<el-main class="filter-menus-box"> <div class="menu-empty" v-show='!list.length || loading && !loading' >The menu information has not been filtered out for the time being, Please select another filter</div> <!--Work display--> <menu-card style="min-height: 75%;" :info="list"></menu-card> <!-- Pagination display --> <div style="text-align: right;" v-show='!loading'> <el-pagination style="display: inline-block;" :page-size="5" layout="total, prev, pager, next" :total="total" :current-page.sync='page' @current-change="handlerSelect" :hide-on-single-page='true' > </el-pagination> </div> </el-main>
After the filtered data is obtained, the loading event is executed. Its value is false. When the loading value is false, the loading will always be executed and will not stop. If its value is always false, its value will be changed to true
getMenus(params).then(({data})=>{ // console.log(data) if(this.loading){ loading.close() } this.loading = false ; this.list = data.list ; this.total = data.total ; this.page = data.current_page ; // If the loading after obtaining the filtered data is always false, re assign it to make its value true if(this.loading === false){ this.loading = true ; } })