[Frontend] Vue+Element UI case: general background management system - breadcrumbs, tag bar


Reference video: VUE project, VUE project actual combat, vue background management system, front-end interview, front-end interview project

the case Link
[Front end] Vue+Element UI case: general background management system - navigation bar (video p1-16) https://blog.csdn.net/karshey/article/details/127640658
[Frontend] Vue+Element UI Case: General Background Management System-Header+Navigation Bar Folding (p17-19) https://blog.csdn.net/karshey/article/details/127652862
[Frontend] Vue+Element UI Case: General Background Management System - Home Components: Cards, Forms (p20-22) https://blog.csdn.net/karshey/article/details/127674643
[Front end] Vue+Element UI case: general background management system - Echarts chart preparation: axios package, mock data simulation actual combat (p23-25) https://blog.csdn.net/karshey/article/details/127735159
[Front end] Vue+Element UI case: general background management system - Echarts chart: line chart, histogram, pie chart (p27-30) https://blog.csdn.net/karshey/article/details/127737979
[Frontend] Vue+Element UI case: general background management system - breadcrumbs, tag bar (p31-35) https://blog.csdn.net/karshey/article/details/127756733
[Frontend] Vue+Element UI case: general background management system - user management: Form filling, Dialog box popping up (p36-38) https://blog.csdn.net/karshey/article/details/127787418
[Front-end] Vue+Element UI case: general background management system-user management: Table table addition, deletion and modification, Pagination paging, search box (p39-42) https://blog.csdn.net/karshey/article/details/127777962
[Frontend] Vue+Element UI case: general background management system - login page Login (p44) https://blog.csdn.net/karshey/article/details/127795302
[Frontend] Vue+Element UI case: general background management system - login page function: login authority jump, route guard, exit (p45-46) https://blog.csdn.net/karshey/article/details/127849502
[Front-end] Vue+Element UI case: general background management system - log in different users to display different menus, dynamically add routes (p47-48) https://blog.csdn.net/karshey/article/details/127865621
[Frontend] Vue+Element UI Case: General Background Management System - Project Summary https://blog.csdn.net/karshey/article/details/127867638

Target

insert image description here

  • Click on the tab bar on the left, if it is not on the breadcrumbs, add it
  • Click on breadcrumbs or tags to perform routing jumps
  • tag can be deleted
  • If the current page is deleted, the routing jumps to the next tag
  • If the current page to be deleted is the last one, jump to the previous one
  • Use vuex to complete communication between components

the code

0. Create components and complete routing

First of all, we don't have components such as Mall and User. We need to create them first and then write them to the route. As for the routes, see the data MenuData:

const MenuData= [
    {
    
    
      path: '/',
      name: 'home',
      label: '首页',
      icon: 's-home',
      url: 'Home/Home'
    },
    {
    
    
      path: '/mall',
      name: 'mall',
      label: '商品管理',
      icon: 'video-play',
      url: 'MallManage/MallManage'
    },
    {
    
    
      path: '/user',
      name: 'user',
      label: '用户管理',
      icon: 'user',
      url: 'UserManage/UserManage'
    },
    {
    
    
      label: '其他',
      icon: 'location',
      children: [
        {
    
    
          path: '/page1',
          name: 'page1',
          label: '页面1',
          icon: 'setting',
          url: 'Other/PageOne'
        },
        {
    
    
          path: '/page2',
          name: 'page2',
          label: '页面2',
          icon: 'setting',
          url: 'Other/PageTwo'
        }
      ]
    }
]

export default MenuData

The index.js under the router is as follows:

import Vue from "vue";
import VueRouter from "vue-router";
import Main from '../Views/Main'
import Home from '../Views/Home.vue'
import Mall from '../Views/Mall.vue'
import User from '../Views/User.vue'
import PageOne from '../Views/PageOne.vue'
import PageTwo from '../Views/PageTwo.vue'
Vue.use(VueRouter)

const routes=[
    // 主路由
    {
    
    
        path:'/',
        component:Main,
        redirect: '/home', // 重定向
        children:[
            // 子路由
            // 这是本次写的部分
            {
    
     path: '/home', name: 'home', component: Home }, // 首页
            {
    
     path: '/user', name: 'user', component: User }, // 用户管理
            {
    
     path: '/mall', name: 'mall', component: Mall }, // 商品管理
            {
    
     path: '/page1', name: 'page1', component: PageOne }, // 页面1
            {
    
     path: '/page2', name: 'page2', component: PageTwo }, // 页面2
        ]
    }
]

const router = new VueRouter({
    
    
    routes
})

export default router

1. Breadcrumbs

Breadcrumbs are placed in the Header. We open Element UI and find the corresponding component:
insert image description here

<el-breadcrumb separator="/">
  <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
  <el-breadcrumb-item><a href="/">活动管理</a></el-breadcrumb-item>
  <el-breadcrumb-item>活动列表</el-breadcrumb-item>
  <el-breadcrumb-item>活动详情</el-breadcrumb-item>
</el-breadcrumb>

Write into CommonHeader:

<div class="l-content">
   <el-button @click="handleMenu" icon="el-icon-menu" size="mini"></el-button>
   <!-- 面包屑 -->
   <el-breadcrumb separator="/">
       <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
   </el-breadcrumb>
</div>

Here we need to dynamically bind the data of the route, and it will be displayed only when a certain route is clicked.

Note : The home page will exist no matter what, so the routing data of the home page is hard-coded in the state of the vuex store, while the others are added dynamically (Array.push)

2. Use Vuex to complete data communication: from Aside and Header to breadcrumbs and tags

Why is there data communication between components? Because we click on the route to jump to Aside, the displayed breadcrumbs are in the Header, and the tag must be displayed in each component, so it needs to write a separate component and put it in Main.

For the communication between components, we use Vuex, which has been used before, so I won’t repeat it in detail.

Add tab.js under the store folder:

  • tagList: In state, data used to represent breadcrumbs
  • selectMenu: In the mutation, the data used to update the breadcrumbs
export default {
    
    
    state: {
    
    
        isCollapse: false,//导航栏是否折叠
        tabList: [
            {
    
    
                path: '/',
                name: 'home',
                label: '首页',
                icon: 's-home',
                url: 'Home/Home'
            }
        ],//面包屑的数据:点了哪个路由,首页是一定有的
    },
    mutations: {
    
    
        // 修改导航栏展开和收起的方法
        CollapseMenu(state) {
    
    
            state.isCollapse = !state.isCollapse
        },
        // 更新面包屑的数据
        SelectMenu(state, item) {
    
    
            // 如果点击的不在面包屑数据中,则添加
            const index = state.tabList.findIndex(val => val.name === item.name)
            if (index === -1) {
    
    
                state.tabList.push(item)
            }
        }
    }
}

To add a breadcrumb section of code to Aside's sidebar click event:

clickItem(item) {
    
    
   // 防止自己跳自己的报错
    if (this.$route.path !== item.path && !(this.$route.path === '/home' && (item.path === '/'))) {
    
    
        this.$router.push(item.path)
    }
    // 面包屑
    this.$store.commit('SelectMenu',item)
}

At this point, as long as the tab is clicked on the sidebar, a routing jump will occur, and if the clicked data is newly generated, it will be added to the tagList . The bold part is the requirement that our code above fulfills.

Next we need to display the data in the tagList in breadcrumbs. Bind data in the breadcrumbs part of the Header: v-for for each tagList:

<!-- 面包屑 -->
<el-breadcrumb separator="/">
    <el-breadcrumb-item v-for="item in tags" 
    :key="item.path" 
    :to="{ path: item.path }">
    {
   
   {item.label}}
    </el-breadcrumb-item>
</el-breadcrumb>

js: mapState It is an auxiliary function. If you don’t understand it, you can read the official document of vuex. Since the purpose of this article is only to do projects, the functions and functions will not be described in detail.

import {
    
     mapState } from 'vuex'
export default {
    
    
    computed: {
    
    
        ...mapState({
    
    
            tags: state => state.tab.tabList
        })
    }
}

Effect: Click all tabs from top to bottom. Clearly the requirements are fulfilled, but the style is wrong.
insert image description here

3. Breadcrumb Style

Breadcrumb style requirements:

  • same row as button
  • center up and down
  • There is a distance from the left button
  • The last word is white (#fff)
  • Words in other colors are gray (#666)

css:

.l-content {
    
    
    display: flex;
    // 上下居中
    align-items: center;

    .el-breadcrumb {
    
    
        margin-left: 15px;

        // deep 强制生效
        /deep/.el-breadcrumb__item {
    
    
            .el-breadcrumb__inner {
    
    
                &.is-link {
    
    
                    color: #666;
                }
            }

            &:last-child {
    
    
                .el-breadcrumb__inner {
    
    
                    color: #fff;
                }
            }
        }
    }
}

Effect:
insert image description here

4. Tag column structure

The tag column must appear on any page, indicating that it must be written as a separate component CommonTags.vue and placed in Main.

insert image description here
Find the tag component in Element UI:
insert image description here

Looking at the script code a little bit, it's obvious that we won't use it.

<el-tag
  v-for="tag in tags"
  :key="tag.name"
  closable
  :type="tag.type">
  {
   
   {tag.name}}
</el-tag>

Attributes that you don't understand in the code can be checked in the documentation. The red box is the attribute that will be used this time:
insert image description here

<template>
    <div class="tabs">
        <!-- closable是否可删除:除了"首页"都可删 -->
        <!-- effect:主题,当前主题是dark,其他事plain -->
        <el-tag v-for="item in tags" :key="item.path" :closable="item.name !== 'home'"
            :effect="item.name === $route.name ? 'dark' : 'plain'">
            {
   
   { item.label }}
        </el-tag>
    </div>
</template>

<script>
import {
      
       mapState } from 'vuex'

export default {
      
      
    computed: {
      
      
        ...mapState({
      
      
            tags: state => state.tab.tabList
        })
    }
}
</script>

<style>

</style>

5. tag event

  • Delete: Click x to delete the corresponding tag and breadcrumbs
  • If the current page is deleted, the routing jumps to the next tag
  • If the current page to be deleted is the last one, jump to the previous one
  • Click: Click which tag to jump to which tag

These two events are: (10,000th sigh, the component is really easy to use)
insert image description here
html:

<el-tag v-for="(item, index) in tags" :key="item.path" :closable="item.name !== 'home'"
    :effect="item.name === $route.name ? 'dark' : 'plain'" @click="changeMenu(item)"
    @close="handleClose(item, index)">
    {
   
   { item.label }}
</el-tag>

Click event:

changeMenu(item) {
    
    
    this.$router.push({
    
     name: item.name })
}

Delete event:

handleClose(item, index) {
    
    
    // 删除面包屑数据
    this.$store.commit('closeTag', item)
    // 如果删除的刚好是自己
    if (item.name === this.$route.name) {
    
    
        const length = this.tags.length
        // 如果删除的是最后一个:跳到前一个
        if (length === index) {
    
    
            this.$router.push({
    
     name: this.tags[index - 1].name })
        }
        // 不是最后一个:往后一个
        else {
    
    
            this.$router.push({
    
     name: this.tags[index].name })
        }
    }
}

tab.js in store, in mutation:

// 删除tag:删除tabList中对应的item
closeTag(state, item) {
    
    
    // 要删除的是state.tabList中的item
    const index = state.tabList.findIndex(val => val.name === item.name)
    state.tabList.splice(index, 1)
}

6. Tag style

.tabs{
    
    
    padding: 20px;

    .el-tag{
    
    
        margin-right: 15px;
        // 鼠标悬停:小手
        cursor: pointer;
    }
}

Effect

insert image description here

total code

Documents modified or newly created in this article

insert image description here

CommonTags.vue

<template>
    <div class="tabs">
        <!-- closable是否可删除:除了"首页"都可删 -->
        <!-- effect:主题,当前主题是dark,其他事plain -->
        <el-tag v-for="(item, index) in tags" :key="item.path" :closable="item.name !== 'home'"
            :effect="item.name === $route.name ? 'dark' : 'plain'" @click="changeMenu(item)"
            @close="handleClose(item, index)">
            {
   
   { item.label }}
        </el-tag>
    </div>
</template>

<script>
import {
      
       mapState } from 'vuex'

export default {
      
      
    methods: {
      
      
        changeMenu(item) {
      
      
            this.$router.push({
      
       name: item.name })
        },
        handleClose(item, index) {
      
      
            // 删除面包屑数据
            this.$store.commit('closeTag', item)
            // 如果删除的刚好是自己
            if (item.name === this.$route.name) {
      
      
                const length = this.tags.length
                // 如果删除的是最后一个:跳到前一个
                if (length === index) {
      
      
                    this.$router.push({
      
       name: this.tags[index - 1].name })
                }
                // 不是最后一个:往后一个
                else {
      
      
                    this.$router.push({
      
       name: this.tags[index].name })
                }
            }
        }
    },
    computed: {
      
      
        ...mapState({
      
      
            tags: state => state.tab.tabList
        })
    }
}
</script>

<style lang="less" scoped>
.tabs{
      
      
    padding: 20px;

    .el-tag{
      
      
        margin-right: 15px;
        // 鼠标悬停:小手
        cursor: pointer;
    }
}
</style>

tab.js

export default {
    
    
    state: {
    
    
        isCollapse: false,//导航栏是否折叠
        tabList: [
            {
    
    
                path: '/',
                name: 'home',
                label: '首页',
                icon: 's-home',
                url: 'Home/Home'
            }
        ],//面包屑的数据:点了哪个路由,首页是一定有的
    },
    mutations: {
    
    
        // 修改导航栏展开和收起的方法
        CollapseMenu(state) {
    
    
            state.isCollapse = !state.isCollapse
        },
        // 更新面包屑的数据
        SelectMenu(state, item) {
    
    
            // 如果点击的不在面包屑数据中,则添加
            const index = state.tabList.findIndex(val => val.name === item.name)
            if (index === -1) {
    
    
                state.tabList.push(item)
            }
        },
        // 删除tag:删除tabList中对应的item
        closeTag(state, item) {
    
    
            // 要删除的是state.tabList中的item
            const index = state.tabList.findIndex(val => val.name === item.name)
            state.tabList.splice(index, 1)
        }
    }
}

router's index.js

import Vue from "vue";
import VueRouter from "vue-router";
import Main from '../Views/Main'
import Home from '../Views/Home.vue'
import Mall from '../Views/Mall.vue'
import User from '../Views/User.vue'
import PageOne from '../Views/PageOne.vue'
import PageTwo from '../Views/PageTwo.vue'
Vue.use(VueRouter)

const routes=[
    // 主路由
    {
    
    
        path:'/',
        component:Main,
        redirect: '/home', // 重定向
        children:[
            // 子路由
            {
    
     path: '/home', name: 'home', component: Home }, // 首页
            {
    
     path: '/user', name: 'user', component: User }, // 用户管理
            {
    
     path: '/mall', name: 'mall', component: Mall }, // 商品管理
            {
    
     path: '/page1', name: 'page1', component: PageOne }, // 页面1
            {
    
     path: '/page2', name: 'page2', component: PageTwo }, // 页面2
        ]
    }
]

const router = new VueRouter({
    
    
    routes
})

export default router

Guess you like

Origin blog.csdn.net/karshey/article/details/127756733#comments_27541248